线段树分裂
作者:互联网
线段树分裂
给自己看的,就挑一下重点
需要动态开点……
用 \(\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