Loading

线段树分而裂之

线段树分裂:

线段树分裂者,算法分治之精要也。其术若庖丁解牛,循理而析。初始,整树为一,犹混沌未分。及至查询区间,则自根始,逐层剖判:若节点全含所求,则裂之为二,左存原枝,右立新干;若仅涉半域,则下探子枝,如禹导江河,各循其道。分裂既成,新树旧木并存,犹宗族之分爨,然血脉相连。凡标记懒传、子息重构,皆合《九章》"少广"之术,此乃计算机之道通于古算之明证也。

【模板】线段树分裂

简要题意:

给出一个可重集 \(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\)

思路:

点击查看

按排名分:

\(Code\):



#include<bits/stdc++.h>
#define int long long
const int N = 6e6+10;
using namespace std;
int T[N],ls[N],rs[N],cnt,rt[N],tot=1,n,m;
int add(int i,int l,int r,int x,int k) {
    if(!i) i=++cnt;
    T[i]+=k;
    if(l==r) return i;
    int mid=l+r>>1;
    if(x<=mid) ls[i]=add(ls[i],l,mid,x,k);
    else rs[i]=add(rs[i],mid+1,r,x,k);
    return i;
}
int get_val(int i,int l,int r,int k) {
    if(l==r) return l;
    int mid=l+r>>1,siz=T[ls[i]];
    if(siz>=k) return get_val(ls[i],l,mid,k);
    else return get_val(rs[i],mid+1,r,k-siz);
}
int get_rank(int i,int l,int r,int x,int tag) {
    if(l==r) return 1+(T[i]-1)*tag;
    int mid=l+r>>1,siz=T[ls[i]];
    if(x<=mid) return get_rank(ls[i],l,mid,x,tag);
    else return get_rank(rs[i],mid+1,r,x,tag)+siz;
}
int merge(int x,int y,int l,int r) {
    if(!x||!y) return x|y;
    T[x]+=T[y];
    if(l==r)return x;
    int mid=l+r>>1;
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    return x;
}
int split(int x,int y,int k) {
    y=++cnt;
    if(!x) return y;
    int siz=T[ls[x]],siz2=T[x];
    if(siz>k) {
        swap(rs[x],rs[y]);
        ls[y]=split(ls[x],ls[y],k);
    }
    else if(siz==k)swap(rs[x],rs[y]);
    else rs[y]=split(rs[x],rs[y],k-siz);
    T[y]=T[x]-k;T[x]=k;
    return y;
}
signed main() {
    cin>>n>>m;
    for(int i=1,x;i<=n;i++) {
        cin>>x;
        rt[tot]=add(rt[tot],1,n,i,x);
    }
    for(int i=1,opt;i<=m;i++) {
        cin>>opt;
        if(opt==0) {
            int p,x,y,nwt=0,nwr=0;
			cin>>p>>x>>y;
			int rxk=get_rank(rt[p],1,n,x,0),ryk=get_rank(rt[p],1,n,y,1);
			rt[++tot]=split(rt[p],rt[tot],rxk-1);
			int lrt=0;lrt=split(rt[tot],lrt,ryk-rxk+1);
			rt[p]=merge(rt[p],lrt,1,n);
        }
        else if(opt==1){
            int x,y;
            cin>>x>>y;
            rt[x]=merge(rt[x],rt[y],1,n);
        }
        else if(opt==2) {
            int p,q,x;
            cin>>p>>x>>q;
            add(rt[p],1,n,q,x);
        }
        else if(opt==3) {
            int p,x,y,nwt=0,nwr=0;
			cin>>p>>x>>y;
			int rxk=get_rank(rt[p],1,n,x,0),ryk=get_rank(rt[p],1,n,y,1),ans=0;
			cout<<ryk-rxk+1<<'\n';
        }
        else {
            int p,k;
            cin>>p>>k;
            if(T[rt[p]]<k) puts("-1");
            else cout<<get_val(rt[p],1,n,k)<<"\n";
        }
    }
    return 0;
}


posted @ 2025-07-02 11:08  dfgz  阅读(33)  评论(1)    收藏  举报