• [SCOI2014]方伯伯的OJ(线段树)


    方伯伯正在做他的Oj。现在他在处理Oj上的用户排名问题。Oj上注册了n个用户,编号为1~n“,一开始他们按照编号排名。

    方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:

    1.操作格式为1 x y,意味着将编号为x的用户编号改为y,而排名不变,执行完该操作后需要输出该用户在队列中的位置,数据保证x必然出现在队列中,同时,1是一个当前不在排名中的编号。

    2.操作格式为2 x,意味着将编号为x的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为x用户的排名。

    3.操作格式为3 x,意味着将编号为x的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为x用户的排名。

    4.操作格式为4 k,意味着查询当前排名为k的用户编号,执行完该操作后需要输出当前操作用户的编号。

    但同时为了防止别人监听自己的工作,方伯伯对他的操作进行了加密,即将四种操作的格式分别改为了:

    • 1 x+a y+a
    • 2 x+a
    • 3 x+a
    • 4 k+a
    • 其中a为上一次操作得到的输出,一开始a=0。

    例如:上一次操作得到的输出是5这一次操作的输入为:1 13 15因为这个输入是经过加密后的,所以你应该处理的操作是1 8 10现在你截获了方伯伯的所有操作,希望你能给出结果。

    Solution

    调了一晚上。。。菜的不行。

    因为数列每次只会变化一个数,所以可以不用splay或fhqtreap,用一颗动态开点线段树就可以完成。

    因为我们的移动只关于先插和后插,所以我们线段树的区间为m+n+m对于一个移动,我们先把该点在对应位置删除,再将该数插入前/后对应位置。

    与此同时,我们开两个map,一个储存编号对应的位置,一个储存位置对应的编号。

    Code

    #include<iostream>
    #include<cstdio>
    #include<map>
    #define ls tr[cnt].l
    #define rs tr[cnt].r
    #define N 200002
    using namespace std;
    map<int,int>mp,anti_mp;
    int tot,id,ans,n,m,root,h,t,x,y;
    struct seg{
        int l,r,num;
        bool la;
    }tr[N*20];
    inline int rd(){
        int x=0;char c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c)){
            x=(x<<1)+(x<<3)+(c^48);
            c=getchar();
        } 
        return x;
    }
    inline void pushdown(int cnt,int l1,int l2){
        if(!ls)ls=++tot;if(!rs)rs=++tot;
        tr[ls].num=l1;tr[rs].num=l2;
        tr[cnt].la=0;tr[ls].la=tr[rs].la=1;
    }
    void add(int &cnt,int l,int r,int x,int tag,int rk){
        if(!cnt)cnt=++tot;
        if(l==r){
            if(tag<0)ans=rk+1,anti_mp.erase(l);
            else anti_mp[l]=id;
            tr[cnt].num-=tag;
            return;
        }
        int mid=(l+r)>>1;
        if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
        if(mid>=x)add(ls,l,mid,x,tag,rk);
        else add(rs,mid+1,r,x,tag,rk+mid-l+1-tr[ls].num); 
        tr[cnt].num=tr[ls].num+tr[rs].num;
    }
    void find(int &cnt,int l,int r,int rk){
        if(!cnt)cnt=++tot;
        if(l==r){
            if(anti_mp.find(l)!=anti_mp.end())ans=anti_mp[l];else ans=l-m;
            return;
        }
        int mid=(l+r)>>1;
        if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
        int num=mid-l+1-tr[ls].num;    
        if(num>=rk)find(ls,l,mid,rk);
        else find(rs,mid+1,r,rk-num);
    }
    void gai(int &cnt,int l,int r,int L,int R){
        if(!cnt)cnt=++tot;
        if(l>=L&&r<=R){
            tr[cnt].num=r-l+1;
            tr[cnt].la=1;
            return; 
        }
        int mid=(l+r)>>1;
        if(mid>=L)gai(ls,l,mid,L,R);
        if(mid<R)gai(rs,mid+1,r,L,R);
        tr[cnt].num=tr[ls].num+tr[rs].num;
    }
    void upd(int &cnt,int l,int r,int x,int y,int rk){
        if(!cnt)cnt=++tot;
        if(l==r){
            anti_mp[l]=y;ans=rk+1;
            return;
        }
        int mid=(l+r)>>1;
        if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid);
        if(mid>=x)upd(ls,l,mid,x,y,rk);
        else upd(rs,mid+1,r,x,y,rk+mid-l+1-tr[ls].num);
    }
    int main(){
        n=rd();m=rd();
        gai(root,1,n+2*m,1,m);
        gai(root,1,n+2*m,n+m+1,n+m*2);
        h=m+1;t=n+m;
        for(int i=1;i<=m;++i){
            int tag=rd();x=rd()-ans;
            if(tag==1){
                y=rd()-ans;
                int pos;
                if(mp.find(x)!=mp.end())pos=mp[x];
                else pos=x+m;
                mp[y]=pos;
                upd(root,1,n+2*m,pos,y,0);
            }
            else if(tag==2){
                int pos;
                if(mp.find(x)!=mp.end())pos=mp[x];
                else pos=x+m;
                if(anti_mp.find(pos)!=anti_mp.end())id=anti_mp[pos];
                else id=x;
                add(root,1,n+2*m,pos,-1,0);
                add(root,1,n+2*m,--h,1,0);
                mp[x]=h;
            }
            else if(tag==3){
                int pos;
                if(mp.find(x)!=mp.end())pos=mp[x];
                else pos=x+m;
                if(anti_mp.find(pos)!=anti_mp.end())id=anti_mp[pos];
                else id=x;
                add(root,1,n+2*m,pos,-1,0);
                add(root,1,n+2*m,++t,1,0);
                mp[x]=t;
            }
            else find(root,1,n+2*m,x);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    JAVA多线程大总结篇
    JAVA多线程总结01
    Eclipse配置Tomcat
    jdbc注册驱动出现Loading class `com.mysql.jdbc.Driver'. This is deprecated的问题:
    windows10环境下eclipse连接mysql
    mysql忘记密码,如何修改
    c++笔记:虚函数必要但易忘的一些性质
    Mysql 4 —— select 进阶
    Mysql 3 —— 建表
    数据结构实验一:单链表就地翻转
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9715245.html
Copyright © 2020-2023  润新知