• [洛谷P3295][SCOI2014]方伯伯的OJ


    题目描述:https://www.luogu.org/problemnew/show/P3285

    解析:首先发现n的范围很大,但m的范围很小,所以被操作的点最多只有1e5个点,于是想到用一个点表示一段区间,要用的时候再拆开。怎么实现呢?想到用一颗平衡树来维护排名,每一个节点记录在原序列中的一段区间的左端点和右端点,用map来维护一段区间的右端点所在节点的编号,这样做就可以快速找到一个值所在splay中的节点编号。这样1操作就可以很顺利的解决了,记得拆开点之后要更新每个节点的L和R以及与m的更新。对于2操作,可先将该节点splay至根,再将根的左儿子直接连向该点的后继,最后将后继的左儿子转到根,这样既能更新子树的大小又能保证时间复杂度。3操作与2同理。对于4操作,直接查k大就可以了。

    细节:好像没什么细节,不要写挂就好。

    附上代码:

    #include<cstdio>
    #include<iostream>
    #include<map>
    #include<algorithm>
    using namespace std;
    
    const int MAXM=1e5+5;
    int n,m;
    struct Node{
        int size,l,r,fa,son[2];
    }node[MAXM<<1];
    map<int,int> mp;
    int root;
    int ndnum=0;
    int ans=0;
    
    inline int read(){
        int ret=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
        while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
        return ret*f;
    }
    
    int new_node(int l,int r){
        int x=++ndnum;
        node[x].fa=node[x].son[0]=node[x].son[1]=0;
        node[x].l=l;node[x].r=r;
        node[x].size=node[x].r-node[x].l+1;
        return x;
    }
    
    void update(int x){
        int lson=node[x].son[0],rson=node[x].son[1];
        node[x].size=node[lson].size+node[rson].size+node[x].r-node[x].l+1;
    }
    
    void split(int pos,int x){
        int lson=0,rson=0; 
        if(node[pos].l==node[pos].r) return;
        mp[x]=pos;
        if(node[pos].l!=x){
            lson=mp[x-1]=new_node(node[pos].l,x-1);
            node[lson].fa=pos;
            node[lson].son[0]=node[pos].son[0];
            node[node[lson].son[0]].fa=lson;
            node[pos].son[0]=lson;
            node[pos].size=1;
        }
        if(node[pos].r!=x){
            rson=mp[node[pos].r]=new_node(x+1,node[pos].r);
            node[rson].fa=pos;
            node[rson].son[1]=node[pos].son[1];
            node[node[rson].son[1]].fa=rson;
            node[pos].son[1]=rson;
            node[pos].size=1;
        }
        node[pos].l=node[pos].r=x;
        if(lson) update(lson);
        if(rson) update(rson);
        update(pos);
    }
    
    int check(int x){
        return x==node[node[x].fa].son[1];
    }
    
    void rotate(int x){
        int y=node[x].fa,z=node[y].fa,d=check(x),xx=node[x].son[d^1];
        node[y].son[d]=xx;node[xx].fa=y;
        node[z].son[check(y)]=x;node[x].fa=z;
        node[x].son[d^1]=y;node[y].fa=x;
        update(y);update(x);
    }
    
    void splay(int x,int to=0){
        while(node[x].fa!=to){
            int y=node[x].fa,z=node[y].fa;
            if(z!=to){
                if(check(x)==check(y)) rotate(y);
                 else rotate(x);
             }
             rotate(x);
        }
        if(!to) root=x;
    }
    
    int rank(int x){
        splay(x);
        return node[node[root].son[0]].size+1;
    }
    
    void merge(int x){
        splay(x);
        if(!node[x].son[0]) return;
        else if(!node[x].son[1]) {swap(node[x].son[0],node[x].son[1]);return;}
        else{
            int cur=node[x].son[1];
            while(node[cur].son[0]) cur=node[cur].son[0];
            int lson=node[x].son[0];
            node[lson].fa=cur;
            node[cur].son[0]=lson;
            node[x].son[0]=0;
            update(node[x].son[1]);update(x);
            splay(lson);
        }
    }
    
    void fmerge(int x){
        splay(x);
        if(!node[x].son[1]) return;
        else if(!node[x].son[0]) {swap(node[x].son[0],node[x].son[1]);return;}
        else{
            int cur=node[x].son[0];
            while(node[cur].son[1]) cur=node[cur].son[1];
            int rson=node[x].son[1];
            node[rson].fa=cur;
            node[cur].son[1]=rson;
            node[x].son[1]=0;
            update(node[x].son[0]);update(x);
            splay(rson);
        }
    }
    
    int find(int kth){
        int cur=root;
        while(1){
            int lson=node[cur].son[0],rson=node[cur].son[1];
            if(kth<=node[lson].size)
                cur=lson;
            else if(kth>node[lson].size+node[cur].r-node[cur].l+1){
                kth-=node[lson].size+node[cur].r-node[cur].l+1;
                cur=rson;
            }
            else{
                kth-=node[lson].size;
                return node[cur].l+kth-1;
            }
        }
    }
    
    int main(){
        n=read();m=read();
        mp[n]=root=new_node(1,n);
        for(int i=1;i<=m;i++){
            int opt=read();
            if(opt==1){
                int x=read(),y=read();
                x-=ans;y-=ans;
                int pos=(*mp.lower_bound(x)).second;
                split(pos,x);
                ans=rank(pos);
                node[pos].l=node[pos].r=y;
                mp[y]=pos;
                printf("%d
    ",ans);
            }
            if(opt==2){
                int x=read();
                x-=ans;
                int pos=(*mp.lower_bound(x)).second;
                split(pos,x);
                ans=rank(pos);
                merge(pos);
                printf("%d
    ",ans);
            }
            if(opt==3){
                int x=read();
                x-=ans;
                int pos=(*mp.lower_bound(x)).second;
                split(pos,x);
                ans=rank(pos);
                fmerge(pos);
                printf("%d
    ",ans);
            }
            if(opt==4){
                int x=read();
                x-=ans; 
                ans=find(x);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JS系统函数
    匿名函数
    使用递归计算1~n之间所有整数的和
    交换两个变量的值
    创建函数,传递一个数字n,返回斐波那契数列的第n的值。
    创建函数function
    打印本世纪(2000~2100)的前10个闰年
    打印九九乘法表
    计算1~100之间所有整数的和
    循环执行
  • 原文地址:https://www.cnblogs.com/JoshDun/p/11232617.html
Copyright © 2020-2023  润新知