线段树分裂
可重集 ( ex权值线段树是吧 )
题目描述
给出一个可重集 \(a\)(编号为 \(1\)),它支持以下操作:
0 p x y:将可重集 \(p\) 中大于等于 \(x\) 且小于等于 \(y\) 的值移动到一个新的可重集中(新可重集编号为从 \(2\) 开始的正整数,是上一次产生的新可重集的编号+1)。
1 p t:将可重集 \(t\) 中的数放入可重集 \(p\),且清空可重集 \(t\)(数据保证在此后的操作中不会出现可重集 \(t\))。
2 p x q:在 \(p\) 这个可重集中加入 \(x\) 个数字 \(q\)。
3 p x y:查询可重集 \(p\) 中大于等于 \(x\) 且小于等于 \(y\) 的值的个数。
4 p k:查询在 \(p\) 这个可重集中第 \(k\) 小的数,不存在时输出 -1。
#include<bits/stdc++.h>
#define int long long
#define F(i,i0,n) for(int i=i0;i<=n;i++)
using namespace std;
inline int rd(){
int f=0,x=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return f?-x:x;
}
const int N=2e6+5;
struct Tr{
int ls,rs,ct;
}tr[N*4];
#define lp (tr[p].ls)
#define rp (tr[p].rs)
#define mid (l+r>>1)
int cnt=0,tot=0;
int rub[N*4];
void del(int p){
tr[p].ls=tr[p].rs=tr[p].ct=0;
rub[++tot]=p;
}
int newnode(){return tot?rub[tot--]:++cnt;}//垃圾桶体系,节省节点
int a[N],n,m;
void pushup(int p){tr[p].ct=tr[lp].ct+tr[rp].ct;}
void merge(int &x,int y,int l=1,int r=n){
if(!x||!y){x|=y;return;}
if(l==r){
tr[x].ct+=tr[y].ct;
return ;
}
merge(tr[x].ls,tr[y].ls,l,mid);
merge(tr[x].rs,tr[y].rs,mid+1,r);
del(y);
pushup(x);
}
void split(int x,int &y,int k){
if(!x)return ;
y=newnode();
int num=tr[tr[x].ls].ct;
if(num<k)split(tr[x].rs,tr[y].rs,k-num);
else swap(tr[x].rs,tr[y].rs);
if(num>k) split(tr[x].ls,tr[y].ls,k);
pushup(x);pushup(y);
}
void update(int &p,int pos,int k,int l=1,int r=n){
if(!p)p=newnode();
if(l==r){
tr[p].ct+=k;
return ;
}
if(pos<=mid)update(lp,pos,k,l,mid);
else update(rp,pos,k,mid+1,r);
pushup(p);
}
int query(int p,int nl,int nr,int l=1,int r=n){
if(!p)return 0;
if(nl==l&&r==nr){
return tr[p].ct;
}
if(nr<=mid)return query(lp,nl,nr,l,mid);
else if(mid<nl)return query(rp,nl,nr,mid+1,r);
else return query(lp,nl,mid,l,mid)+query(rp,mid+1,nr,mid+1,r);
}
int kth(int p,int k,int l=1,int r=n){
if(l==r)return l;
if(tr[lp].ct>=k)return kth(lp,k,l,mid);
else return kth(rp,k-tr[lp].ct,mid+1,r);
}
#undef lp
#undef rp
#undef mid
int rt[N];
signed main(){
n=rd(),m=rd();
F(i,1,n){
int x=rd();
update(rt[1],i,x);
}
int id=1;
while(m--){
int op=rd();
if(!op){
int p=rd(),x=rd(),y=rd();++id;
int k1=query(rt[p],1,y),k2=query(rt[p],x,y),tmp;
split(rt[p],rt[id],k1-k2);
split(rt[id],tmp,k2);
merge(rt[p],tmp);
}
else if(op==1){
int p=rd(),t=rd();
merge(rt[p],rt[t]);
}
else if(op==2){
int p=rd(),x=rd(),q=rd();
update(rt[p],q,x);
}
else if(op==3){
int p=rd(),x=rd(),y=rd();
cout<<query(rt[p],x,y)<<'\n';
}
else {
int p=rd(),k=rd();
if(tr[rt[p]].ct<k)cout<<-1<<'\n';
else cout<<kth(rt[p],k)<<'\n';
}
}
return 0;
}

浙公网安备 33010602011771号