其他分享
首页 > 其他分享> > 线段树分裂

线段树分裂

作者:互联网

线段树分裂

给自己看的,就挑一下重点

需要动态开点……

用 \(\rm new\) 函数的话也没什么,不过不能写回收栈了,直接 \(\rw delete\) 即可

\(split\)

类似于主席树,直接指针指过去即可,记得要把原指针清掉

剩下的细节都在代码里写了

#include <bits/stdc++.h>

using namespace std;

#define int long long 
const int mod = 1e9 + 7;

template<typename _T>
inline void read(_T &x)
{
	x = 0;int f= 1;char s = getchar();
	while(s<'0'||s>'9'){f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

const int np = 2e5 + 5;

int ind = 1;

struct Node{
	int l,r;
	Node *ls,*rs;
	int num;
	
	Node(int L,int R)
	{
		l = L,r = R;
		ls = rs = NULL;
		num = 0;
	}
	
	inline bool inrange(int L,int R){return L<=l&&r<=R;}
	inline bool outofrange(int L,int R){return r<L||R<l;}
	
	inline void pushdown()
	{
		int mid = l+r>>1;
		if(!ls) ls = new Node(l , mid);
		if(!rs) rs = new Node(mid + 1 , r);
	}
	
	inline void pushup()
	{
		int ln=0,rn=0;
		if(l == r) return;//这个一定得判,不然到叶子节点会挂
		if(ls) ln = ls->num;
		if(rs) rn = rs->num;
		num = ln + rn;
	}
	
	inline void insert(int x,int val)
	{
		if(inrange(val,val))
		{
			num+=x;
			return;
		}
		else
		{
			if(!outofrange(val,val))
			{
				pushdown();
				ls->insert(x,val);
				rs->insert(x,val);
				pushup();
			}
			return ;
		}
	}
	
	inline int query(int kth)//线段树上二分
	{
		if(kth > num) return -1;
		if(!ls && !rs)
		{
			return l;
		}
		else
		{
			int ln=0;
			if(ls) ln = ls->num;
			if(kth <= ln) return ls->query(kth);
			else return rs->query(kth - ln);
		}
	}
	
	inline int query(int L,int R)
	{
		if(inrange(L,R))
		{
			return num;
		}
		else
		{
			if(!outofrange(L,R))
			{
				int ln = 0,rn = 0;
				if(ls) ln = ls->query(L,R);
				if(rs) rn = rs->query(L,R);
				return ln + rn;
			}
			else return 0;
		}
	}
}*rot[np + 10];

inline Node *merge(Node *u ,Node *&pre,int l,int r)
{
	if(!pre) return u;
	if(!u) return pre;
	u->num += pre->num;
	int mid = l+r>>1;
	u->ls = merge(u->ls , pre->ls , l , mid);
	u->rs = merge(u->rs , pre->rs , mid + 1 , r);
	delete(pre);//空间卡的紧的话能删就删
	pre = NULL;
	u->pushup();//一定要上传!
	return u;
}

inline void split(Node *u , Node *&pre,int L,int R)//pre传指针的地址
{
	if(pre->inrange(L,R))
	{
		*u = *pre;
		pre = NULL;
		return;
	}
	else
	{
		if(!pre->outofrange(L,R))
		{
			int l = pre->l , r = pre->r;
			int mid = l + r >> 1;
			if(pre->ls) split(u->ls = new Node(l,mid), pre->ls , L,R);
			if(pre->rs) split(u->rs = new Node(mid+1,r), pre->rs , L,R); 
			if(!pre->ls && !pre->rs) pre = NULL;//记得判NULL
			else pre->pushup();
			u->pushup();//一定要上传
		}
		else return ;
	}
}

signed main()
{
	int n,m;
	read(n);
	read(m);
	
	rot[ind] = new Node(1,n);
	
	for(int i=1,x;i<=n;i++)
	{
		read(x);
		rot[ind]->insert(x , i);
	}
	
	for(int i=1,p,x,y,t,opt,q,k;i<=m;i++)
	{
		read(opt);
		switch(opt)
		{
			case 0:{
				read(p);
				read(x);
				read(y);
				rot[++ind] = new Node(1,n);
				if(!rot[p]) continue;
				split(rot[ind],rot[p],x,y);
				break;
			}
			case 1:{
				read(p);
				read(t);
				rot[p] = merge(rot[p],rot[t],1,n);
				break;
			}
			case 2:{
				read(p);
				read(x);
				read(q);
				if(!rot[p]) rot[p] = new Node(1,n);
				rot[p]->insert(x,q);
				break;
			}
			case 3:{
				read(p);
				read(x);
				read(y);
				if(!rot[p])
				{
					printf("0\n");
					continue;
				}
				int la = rot[p]->query(x,y);
				printf("%lld\n",la);
				break;
			}
			case 4:{
				read(p);
				read(k);
				if(!rot[p])
				{
					printf("-1\n");
					continue;
				}
				int la = rot[p]->query(k);
				printf("%lld\n",la);
				break;
			}
		}
	}
}

标签:pre,Node,return,rs,int,线段,分裂,ls
来源: https://www.cnblogs.com/-Iris-/p/15350276.html