【Luogu】P3380树套树模板(线段树套Splay)

  题目链接

  幸甚至哉,歌以咏志。

  拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树。

  每道模板都是链上的一颗珠子。把它们挨个串起来,就成为我成长的历程。

  抒情结束开始讲题

  这道题我们用线段树存平衡树的根节点。比如我们有一棵线段树

  

  这样子。线段树的一个节点   存   它表示的那个区间   所对应的  平衡树   的根节点编号。这样每个节点都拥有一棵平衡树。是不是很炫呢?

  对于操作1我们就可以把所有零散的区间里比它小的数的个数都找出来,+1就是答案啦。

  对于操作2我们可以二分数,然后不断地进行操作1.

  对于操作3我们用logn的时间把所有包含这个点的区间都修改一遍。

  对于操作4和操作5,不多讲了。

  很炫吧

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#define mid ((l+r)>>1)
#define left (rt<<1)
#define right (rt<<1|1)
#define lson l,mid,left
#define rson mid+1,r,right

using std::max;
using std::min;

inline int read(){
    int num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int s[502000];
int q[102000];

struct Node{
    int e[2],fa,val,size,sum;
}tree[5002000];
int tot,point;
inline void update(int x){
    tree[x].size=tree[x].sum;
    if(tree[x].e[0])    tree[x].size+=tree[tree[x].e[0]].size;
    if(tree[x].e[1])    tree[x].size+=tree[tree[x].e[1]].size;
}
inline void connect(int x,int fa,int how){    tree[x].fa=fa;    tree[fa].e[how]=x;    }
inline int iden(int x){    return x==tree[tree[x].fa].e[1];    }
void rotate(int x,int rt){
    int y=tree[x].fa;    int r=tree[y].fa;
    if(y==s[rt])    s[rt]=x;
    int sony=iden(x);    int sonr=iden(y);
    int b=tree[x].e[sony^1];
    connect(b,y,sony);
    connect(y,x,sony^1);
    connect(x,r,sonr);
    update(y);    update(x);
}

void splay(int pos,int to,int rt){
    to=tree[to].fa;
    while(tree[pos].fa!=to){
        if(tree[tree[pos].fa].fa==to)    rotate(pos,rt);
        else
            if(iden(pos)==iden(tree[pos].fa)){    rotate(tree[pos].fa,rt);    rotate(pos,rt);    }
            else    {    rotate(pos,rt);    rotate(pos,rt);    }
    }
}

inline int create(int val,int fa){
    tree[++tot].val=val;
    tree[tot].fa=fa;
    tree[tot].sum=tree[tot].size=1;
    return tot;
}

inline void Delete(int x){
    tree[x].e[0]=tree[x].e[1]=0;
    if(x==tot)    tot--;
}

int build(int val,int rt){
    point++;
    if(!s[rt]){    s[rt]=create(val,0);    return s[rt];}
    else{
        int now=s[rt];
        while(1){
            tree[now].size++;
            if(val==tree[now].val){    tree[now].sum++;    return now;    }
            int nxt=val<tree[now].val?0:1;
            if(!tree[now].e[nxt]){
                create(val,now);
                tree[now].e[nxt]=tot;
                return tot;
            }
            now=tree[now].e[nxt];
        }
    }
    return 0;
}

inline void insert(int val,int rt){
    int p=build(val,rt);
    splay(p,s[rt],rt);
}

int find(int val,int rt){
    int now=s[rt];
    while(now){
        if(tree[now].val==val){    splay(now,s[rt],rt);    return now;    }
        int nxt=val>tree[now].val;
        if(!tree[now].e[nxt])    return 0;
        now=tree[now].e[nxt];
    }
}

void pop(int val,int rt){
        int deal=find(val,rt);
        if(!deal)    return;
        point--;
        if(tree[deal].sum>1){    tree[deal].sum--;    tree[deal].size--;    return;    }
        if(!tree[deal].e[0]){    s[rt]=tree[deal].e[1];    tree[s[rt]].fa=0;    }
        else{
            int le=tree[deal].e[0];
            while(tree[le].e[1])    le=tree[le].e[1];
            splay(le,tree[deal].e[0],rt);
            int ri=tree[deal].e[1];
            connect(ri,le,1);    s[rt]=le;
            update(le);
        }
        Delete(deal);
}

int rank(int val,int rt){
    int ans=0,now=s[rt];
    while(1){
        //printf("%d %d
",now,tree[now].sum);
        if(val<tree[now].val){
            now=tree[now].e[0];
            if(!now)    return ans;
        }
        else{
            if(tree[now].e[0])    ans+=tree[tree[now].e[0]].size;
            if(val==tree[now].val||!tree[now].e[1]){
                if(val>tree[now].val)    ans+=tree[now].sum;
                splay(now,s[rt],rt);
                return ans;
            }
            ans+=tree[now].sum;    now=tree[now].e[1];
        }
    }
}

inline int lower(int val,int rt){
    int ans=-2147483647,now=s[rt];
    while(1){
        if(!now)    return ans;
        if(tree[now].val<val&&tree[now].val>ans)    ans=tree[now].val;
        int nxt=val>tree[now].val?1:0;
        now=tree[now].e[nxt];
    }
}

inline int upper(int val,int rt){
    int ans=2147483647,now=s[rt];
    while(1){
        if(!now)    return ans;
        if(tree[now].val>val&&tree[now].val<ans)    ans=tree[now].val;
        int nxt=val>tree[now].val?1:0;
        now=tree[now].e[nxt];
    }
}

int lows(int val,int rt){
    int ans=-2147483647,now=s[rt];
    while(1){
        if(!now)    return ans;
        if(tree[now].val<=val&&tree[now].val>ans)    ans=tree[now].val;
        if(tree[now].val==val)    return ans;
        int nxt=val>tree[now].val?1:0;
        now=tree[now].e[nxt];
    }
}

void Build(int l,int r,int rt){
    if(l>r)    return;
    if(l==r){
        insert(q[l],rt);
        return;
    }
    Build(lson);
    Build(rson);
    for(int i=l;i<=r;++i)    insert(q[i],rt);
    return;
}

int findrank(int from,int to,int num,int l,int r,int rt){
    if(from<=l&&to>=r)    return rank(num,rt);
    int ans=0;
    if(from<=mid)    ans+=findrank(from,to,num,lson);
    if(to>mid)        ans+=findrank(from,to,num,rson);
    return ans;
}

void Update(int o,int num,int l,int r,int rt){
    pop(q[o],rt);
    insert(num,rt);
    if(l==r)    return;
    if(o<=mid)    Update(o,num,lson);
    else        Update(o,num,rson);
}

int findlower(int from,int to,int num,int l,int r,int rt){
    if(from<=l&&to>=r)    return lower(num,rt);
    int ans=-2147483647;
    if(from<=mid)    ans=max(ans,findlower(from,to,num,lson));
    if(to>mid)        ans=max(ans,findlower(from,to,num,rson));
    return ans;
}

int findupper(int from,int to,int num,int l,int r,int rt){
    if(from<=l&&to>=r)    return upper(num,rt);
    int ans=2147483647;
    if(from<=mid)    ans=min(ans,findupper(from,to,num,lson));
    if(to>mid)        ans=min(ans,findupper(from,to,num,rson));
    return ans;
}

int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;++i)    q[i]=read();
    Build(1,n,1);
    for(register int i=1;i<=m;++i){
        int opt=read();
        if(opt==1){
            int l=read(),r=read(),q=read();
            printf("%d
",findrank(l,r,q,1,n,1)+1);
        }
        else if(opt==2){
            int l=read(),r=read(),q=read();
            int a=0,b=1e8,Ans=0;
            while(a<=b){
                int m=(a+b)>>1;
                int x=lows(m,1);
                if(findrank(l,r,x,1,n,1)+1>q)    b=m-1;
                else{
                    a=m+1;
                    Ans=x;
                }
            }
            printf("%d
",Ans);
        }
        else if(opt==3){
            int l=read(),r=read();
            Update(l,r,1,n,1);
            q[l]=r;
        }
        else if(opt==4){
            int l=read(),r=read(),q=read();
            printf("%d
",findlower(l,r,q,1,n,1));
        }
        else if(opt==5){
            int l=read(),r=read(),q=read();
            printf("%d
",findupper(l,r,q,1,n,1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8041493.html