zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    什么是理想?
    leetcode 62. 不同路径-动态规划及优化,双100%
    使用双指针暴力解决力扣28题《实现 strStr()》
    使用双指针解决力扣27题《移除元素》
    SQL SERVER 数据库日志已满时清理日志的方法
    修改git提交的名字和邮箱
    React Native运行出现Could not find "iPhone X" simulator
    eosio 编译与部署
    恢复经常写博客的习惯
    MAC OS系统替换homebrew使用阿里云或中科大的镜像源
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8041493.html
Copyright © 2011-2022 走看看