洛谷P5494 模板线段树分裂

Posted Code Fan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷P5494 模板线段树分裂相关的知识,希望对你有一定的参考价值。

传送门

  需要的前置知识:线段树合并。

  感觉会了线段树合并这个就很简单,线段树分裂就是在把一颗权值线段树值域在[x, y]的区间分裂出来单独成一个线段树,那么我们只需要从新树q和旧树p的根节点一起走,如果走到当前p被[x, y]完全包含的路径就把p的编号给q,并且把p改为0就行了,注意这里p和q要传引用,并且不能直接拿q = p这样p和q的地址会一样,所以一改开一个int类型tmp = p,q = tmp,p = 0然后我们return即可,然后注意这题卡空间需要废点优化,我们把线段树合并不需要的那一部分点存进stk数组,并且将这个结点的tr清空即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
#include <deque>
#include <vector>

typedef long long ll;
typedef std::pair<int, int> PII;
#define ls tr[u].l
#define rs tr[u].r

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10, M = 2e5 + 10;

int n, m;

int root[N], cnt, a[N];
int stk[N << 5], top;

struct node 
	int l, r;
	ll cnt;
tr[N << 5];

inline int get() 
	if(!top) 
		return ++ cnt;
	 

	int p = stk[top --];
	tr[p] = 0, 0, 0;
	
	return p;


inline void pushup(int u) 
	tr[u].cnt = tr[tr[u].l].cnt + tr[tr[u].r].cnt;


inline void build(int &u, int L, int R) 
	u = get();
	if(L == R) 
	
		tr[u].cnt = a[L];
		return ;
	 
	
	int mid = L + R >> 1;
	build(tr[u].l, L, mid);
	build(tr[u].r, mid + 1, R);
	
	pushup(u);


inline void split(int &p, int &q, int L, int R, int x, int y) 
	if(!q) q = get();
	if(L >= x && R <= y) 
		q = p;
		p = 0;
		return ;
	
	
	int mid = L + R >> 1;
	if(x <= mid)	split(tr[p].l, tr[q].l, L, mid, x, y);
	if(y > mid)	split(tr[p].r, tr[q].r, mid + 1, R, x, y);
	
	pushup(p);
	pushup(q);


inline int merge(int p, int q, int L, int R)
	if(!p)	return q;
	if(!q)	return p;
	stk[++ top] = q;
	if(L == R)
		tr[p].cnt += tr[q].cnt;
		return p;
		
	int mid = L + R >> 1;
	tr[p].l = merge(tr[p].l, tr[q].l, L, mid);
	tr[p].r = merge(tr[p].r, tr[q].r, mid + 1, R);

	pushup(p);
	return p;


inline void insert(int &p, int L, int R, ll x, int v) 
	if(!p) p = get();
	if(L == R) 
		tr[p].cnt += x;
		return ;
	
	
	int mid = L + R >> 1;
	if(v <= mid)	insert(tr[p].l, L, mid, x, v);
	else insert(tr[p].r, mid + 1, R, x, v);
	
	pushup(p);


inline ll query(int p, int L, int R, int x, int y) 
	if(!p)	return 0;

	if(L >= x && R <= y)	return tr[p].cnt;
	
	int mid = L + R >> 1;
	ll res = 0;
	
	if(x <= mid)	res += query(tr[p].l, L, mid, x, y);
	if(y > mid) res += query(tr[p].r, mid + 1, R, x, y);
	
	return res;


inline int queryk(int p, int L, int R, ll k) 
	if(L == R)	return L;
	int mid = L + R >> 1;
	if(tr[tr[p].l].cnt < k) 	return queryk(tr[p].r, mid + 1, R, k - tr[tr[p].l].cnt);
	return queryk(tr[p].l, L, mid, k);


inline void solve() 
	std::cin >> n >> m;

	for (int i = 1; i <= n; i ++)	std::cin >> a[i];
	build(root[1], 1, n);
	
	int timestap = 1;
	for (int i = 1; i <= m; i ++) 
		int op;
		std::cin >> op;
		if (!op) 
			int p, x, y;
			std::cin >> p >> x >> y;
			split(root[p], root[++ timestap], 1, n, x, y);
	
		 else if (op == 1) 
			int p, q;
			std::cin >> p >> q;
			merge(root[p], root[q], 1, n);
			
			tr[root[i]].cnt << \'\\n\';
		 else if (op == 2) 
			int p, v;
			ll x;
			std::cin >> p >> x >> v;
			insert(root[p], 1, n, x, v);

		 else if (op == 3) 
			int p, x, y;
			std::cin >> p >> x >> y;
			std::cout << query(root[p], 1, n, x, y) << \'\\n\';
		 else 
			 int p;
			 ll k;
			 std::cin >> p >> k;
			 
			 if(tr[root[p]].cnt < k)	std::cout << "-1" << \'\\n\';
			 else std::cout << queryk(root[p], 1, n, k) << \'\\n\';
		
	


int main(void) 
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    
   //freopen("D:\\\\in.txt","r",stdin); //输入重定向,输入数据将从D盘根目录下的in.txt文件中读取 
    int _ = 1;
    //std::cin >> _;
    while(_ --)
    	solve();

    return 0;

		

洛谷P3372线段树模板1——线段树

题目:https://www.luogu.org/problemnew/show/P3372

线段树模板。

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,a[100005],ct;
struct N{
	long long lazy,sum;
	long long ls,rs;
}p[200005];
void pushdown(long long cur,long long l,long long r)
{
	long long mid=(l+r)/2;
	long long lson=p[cur].ls,rson=p[cur].rs;
	p[lson].lazy+=p[cur].lazy;
	p[rson].lazy+=p[cur].lazy;
	p[lson].sum+=p[cur].lazy*(mid-l+1);
	p[rson].sum+=p[cur].lazy*(r-mid);
	p[cur].lazy=0;
}
void pushup(long long cur)
{
	long long lson=p[cur].ls,rson=p[cur].rs;
	p[cur].sum=p[lson].sum+p[rson].sum;
}
void build(long long l,long long r,long long cur)
{
	if(l==r)
	{
		p[cur].sum=a[l];
		p[cur].ls=-1;p[cur].rs=-1;
		return;
	}
	long long mid=(l+r)/2;
	p[cur].ls=++ct;p[cur].rs=++ct;
	build(l,mid,p[cur].ls);build(mid+1,r,p[cur].rs);
	pushup(cur);
}
void add(long long l,long long r,long long L,long long R,long long c,long long cur)
{
	if(l>=L&&r<=R)
	{
		p[cur].lazy+=c;
		p[cur].sum+=c*(r-l+1);
		return;
	}
	pushdown(cur,l,r);//
	long long mid=(l+r)/2;
	if(mid<R)add(mid+1,r,L,R,c,p[cur].rs);
	if(mid>=L)add(l,mid,L,R,c,p[cur].ls);
	pushup(cur);//
}
long long query(long long l,long long r,long long L,long long R,long long cur)
{
	long long tot=0;
	if(l>=L&&r<=R)
		return p[cur].sum;
	long long mid=(l+r)/2;
	pushdown(cur,l,r);
	if(mid<R)tot+=query(mid+1,r,L,R,p[cur].rs);
	if(mid>=L)tot+=query(l,mid,L,R,p[cur].ls);
	return tot;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	for(long long i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	long long rt=++ct;
	build(1,n,rt);
	long long d,x,y,k;
	for(long long i=1;i<=m;i++)
	{
		scanf("%d",&d);
		if(d==1)
		{
			scanf("%lld%lld%lld",&x,&y,&k);
			add(1,n,x,y,k,rt);
		}
		if(d==2)
		{
			scanf("%lld%lld",&x,&y);
			printf("%lld\n",query(1,n,x,y,rt));
		}
	}
	return 0;
}

  

以上是关于洛谷P5494 模板线段树分裂的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P3372线段树模板1——线段树

洛谷P3372 模板线段树 1

[模板]洛谷T3373 线段树 模板2

[模板]洛谷T3372 线段树 模板1

洛谷 3391 模板文艺平衡树 Treap区间翻转

模板线段树 1(洛谷_3372)