线段树合并/分裂

你说的对,但是你理应会动态开点线段树是什么东西。

合并很简单,两棵线段树一块搜,然后逐个节点合并。

分裂的话可以按照 FHQ Treap 的方法。假如我们将前 \(k\) 小和后边分开成 \(x,y\),首先看左子树,如果比 \(k\) 大那右子树给 \(y\),递归左子树,反之左子树给 \(x\),递归右子树。

真没啥好说的,存个板子得了。值得注意的其实是垃圾回收怎么写,以前没写过。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#define int long long
#define lson tree[rt].ls
#define rson tree[rt].rs
using namespace std;
int n,m,cnt,num,buf[200010<<5];
struct node{
    int ls,rs,val;
}tree[200010<<5];
int t,rt[200010];
int New(){
    return cnt?buf[cnt--]:++t;
}
void del(int x){
    buf[++cnt]=x;tree[x].ls=tree[x].rs=tree[x].val=0;
}
void pushup(int rt){
    tree[rt].val=tree[lson].val+tree[rson].val;
}
void update(int &rt,int L,int R,int pos,int val){
    if(!rt)rt=New();
    if(L==R){
        tree[rt].val+=val;return;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)update(lson,L,mid,pos,val);
    else update(rson,mid+1,R,pos,val);
    pushup(rt);
}
int query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r)return tree[rt].val;
    int mid=(L+R)>>1,val=0;
    if(l<=mid)val+=query(lson,L,mid,l,r);
    if(mid<r)val+=query(rson,mid+1,R,l,r);
    return val;
}
int querykth(int rt,int L,int R,int k){
    if(L==R)return L;
    int mid=(L+R)>>1;
    if(tree[lson].val>=k)return querykth(lson,L,mid,k);
    else return querykth(rson,mid+1,R,k-tree[lson].val);
}
int merge(int x,int y,int l,int r){
    if(!x||!y)return x|y;
    if(l==r){
        tree[x].val+=tree[y].val;del(y);
        return x;
    }
    int mid=(l+r)>>1;
    tree[x].ls=merge(tree[x].ls,tree[y].ls,l,mid);
    tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,r);
    pushup(x);del(y);
    return x;
}
void split(int x,int &y,int k){
    if(!x)return;
    y=New();
    int val=tree[tree[x].ls].val;
    if(k>val)split(tree[x].rs,tree[y].rs,k-val);
    else swap(tree[x].rs,tree[y].rs);
    if(k<val)split(tree[x].ls,tree[y].ls,k);
    tree[y].val=tree[x].val-k;tree[x].val=k;
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        int x;scanf("%lld",&x);
        update(rt[1],1,n,i,x);
    }
    num=1;
    while(m--){
        int od,p,x,y;scanf("%lld",&od);
        if(od==0){
            scanf("%lld%lld%lld",&p,&x,&y);
            int k1=query(rt[p],1,n,1,y),k2=query(rt[p],1,n,x,y);
            int tmp=0;
            split(rt[p],rt[++num],k1-k2);
            split(rt[num],tmp,k2);
            rt[p]=merge(rt[p],tmp,1,n);
        }
        else if(od==1){
            scanf("%lld%lld",&x,&y);
            rt[x]=merge(rt[x],rt[y],1,n);
        }
        else if(od==2){
            scanf("%lld%lld%lld",&p,&x,&y);
            update(rt[p],1,n,y,x);
        }
        else if(od==3){
            scanf("%lld%lld%lld",&p,&x,&y);
            printf("%lld\n",query(rt[p],1,n,x,y));
        }
        else{
            scanf("%lld%lld",&p,&x);
            if(tree[rt[p]].val<x)puts("-1");
            else printf("%lld\n",querykth(rt[p],1,n,x));
        }
    }
    return 0;
}
posted @ 2023-05-02 18:04  gtm1514  阅读(11)  评论(0编辑  收藏  举报