ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线段树分裂

2021-09-28 22:03:09  阅读:128  来源: 互联网

标签:pre Node return rs int 线段 分裂 ls


线段树分裂

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

需要动态开点……

用 \(\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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有