[SCOI2014]方伯伯的OJ

这里写图片描述
数据范围 n<=108,m<=105 n <= 10 8 , m <= 10 5
一眼平衡树。5分钟出思路,调了3小时。
我们不好直接维护排名的平衡树,也不好直接维护编号的平衡树。
那就建 2 2 颗平衡树,一棵以编号中序遍历,一棵以排名中序遍历,每个节点开pair记录下这排名和编号。
然后对于每个操作 直接按照题意去修改就好了。把连续的区间缩成点用的时候再拆开。
注意以编号中序遍历中 pair p a i r 的排名并不是真实排名而是相对排名,需要到另一棵树中再查找。
findsz f i n d s z 操作中如果要找的点被那段区间包含了 就直接强行 split s p l i t 拆开返回 sz s z

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e6+5;

typedef pair<int,int>par;
#define mp make_pair

struct treap{
    par val[MAXN];
    int prio[MAXN],size[MAXN],lson[MAXN],rson[MAXN],lm[MAXN],rm[MAXN],rt,cnt;
    inline int get(int p){
        return rm[p]-lm[p]+1;
    }
    inline void pushup(int p){
        size[p]=size[lson[p]]+size[rson[p]]+get(p);
    }
    inline int newnode(int l,int r){
        ++cnt;
        if(l==r)val[cnt].first=l,val[cnt].second=l;
        prio[cnt]=rand();size[cnt]=1;
        lson[cnt]=rson[cnt]=0;lm[cnt]=l,rm[cnt]=r;
        return cnt;
    }
    par split(int p,int x){
        if(!x)return mp(0,p);
        int l=lson[p],r=rson[p];
        if(x<=size[l]){
            par tem=split(l,x);
            lson[p]=tem.second;pushup(p);return mp(tem.first,p);
        }
        else if(x>=size[l]+get(p)){
            par tem=split(r,x-size[l]-get(p));
            rson[p]=tem.first;pushup(p);return mp(p,tem.second);    
        }
        x-=size[l];
        int tem=rm[p];rm[p]=lm[p]+x-1;
        if(rm[p]==lm[p])val[p]=mp(lm[p],lm[p]);
        int pp=newnode(rm[p]+1,tem);
        pp=merge(pp,r);rson[p]=0;
        pushup(p);pushup(pp);
        return mp(p,pp);
    }
    int merge(int x,int y){
        if(!x){pushup(y);return y;}
        if(!y){pushup(x);return x;}
        if(prio[x]<prio[y]){
            rson[x]=merge(rson[x],y);pushup(x);return x;
        }
        lson[y]=merge(x,lson[y]);pushup(y);return y;
    }
    int Split(int p,int v,int posp){
        int l=lm[p],r=rm[p],sz=v-l;
        par t1=split(rt,posp+sz);
        par t2=split(t1.second,1);
        rt=merge(t1.first,merge(t2.first,t2.second));
        return posp+sz;
    }
    int findsz(int x){
        int p=rt,sz=0;
        while(p){
            if(rm[p]>=x&&lm[p]<=x&&rm[p]-lm[p])
                return size[lson[p]]+Split(p,x,sz); 
            if(rm[p]-lm[p]==0){//对于单个点 
                if(val[p].first==x)return size[lson[p]]+sz;
                if(val[p].first>x)p=lson[p];
                else sz+=size[lson[p]]+get(p),p=rson[p];    
            }
            else {//区间 
                if(rm[p]>x)p=lson[p];
                else sz+=size[lson[p]]+get(p),p=rson[p];
            }
        }
        return sz;
    }
    void debug(int p){
        if(lson[p])debug(lson[p]);
        printf("%d ",val[p].second);
        if(rson[p])debug(rson[p]);
    }
}T[2];

int n,m,minn=0,maxx;

int change(int x,int y){
    int pos=T[0].findsz(x);
    par t1=T[0].split(T[0].rt,pos);
    par t2=T[0].split(t1.second,1);
    T[0].val[t2.first].first=y;
    int ret=T[0].val[t2.first].second;
    int put=T[1].findsz(ret)+1;
    printf("%d\n",put);
    T[0].rt=T[0].merge(t1.first,t2.second);
    int pos2=T[0].findsz(y);
    t1=T[0].split(T[0].rt,pos2);
    T[0].rt=T[0].merge(t1.first,T[0].merge(t2.first,t1.second));

    t1=T[1].split(T[1].rt,put-1);
    t2=T[1].split(t1.second,1);
    T[1].val[t2.first].second=y;
    T[1].rt=T[1].merge(t1.first,T[1].merge(t2.first,t2.second));
    return put;
}

int up(int x){
    int pos=T[0].findsz(x);
    par t1=T[0].split(T[0].rt,pos);
    par t2=T[0].split(t1.second,1);
    int ret=T[0].val[t2.first].second;
    int put=T[1].findsz(ret)+1;
    printf("%d\n",put);
    T[0].val[t2.first].second=--minn;
    T[0].rt=T[0].merge(t1.first,T[0].merge(t2.first,t2.second));

    t1=T[1].split(T[1].rt,put-1);
    t2=T[1].split(t1.second,1);
    T[1].val[t2.first].first=minn;
    T[1].rt=T[1].merge(t2.first,T[1].merge(t1.first,t2.second));
    return put;
}

int down(int x){
    int pos=T[0].findsz(x);
    par t1=T[0].split(T[0].rt,pos);
    par t2=T[0].split(t1.second,1);
    int ret=T[0].val[t2.first].second;
    int put=T[1].findsz(ret)+1;
    printf("%d\n",put);
    T[0].val[t2.first].second=++maxx;
    T[0].rt=T[0].merge(t1.first,T[0].merge(t2.first,t2.second));

    t1=T[1].split(T[1].rt,put-1);
    t2=T[1].split(t1.second,1);
    T[1].val[t2.first].first=maxx;
    T[1].rt=T[1].merge(t1.first,T[1].merge(t2.second,t2.first));
    return put;
}

int query(int x){
    int p=T[1].rt,ans=0;
    while(p){
        if(ans+T[1].size[T[1].lson[p]]+T[1].get(p)<x){
            ans+=T[1].size[T[1].lson[p]]+T[1].get(p);
            p=T[1].rson[p];
        }
        else if(ans+T[1].size[T[1].lson[p]]>=x)
            p=T[1].lson[p];
        else {
            if(T[1].rm[p]==T[1].lm[p]){
                printf("%d\n",T[1].val[p].second);
                return T[1].val[p].second;
            }
            else {
                x-=ans+T[1].size[T[1].lson[p]];
                printf("%d\n",T[1].lm[p]+x-1);
                return T[1].lm[p]+x-1;  
            }
        }
    }
}

int main(){
    int x,y;
    scanf("%d%d",&n,&m);
    minn=0,maxx=n+1;
    T[0].rt=T[0].newnode(1,n);T[1].rt=T[1].newnode(1,n);
    int pre=0;
    for(int i=1;i<=m;i++){
        int opt;
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d",&x,&y);
            pre=change(x-pre,y-pre);
        //  T[1].debug(T[1].rt);puts("one");
        }
        else if(opt==2){
            scanf("%d",&x);
        //  T[1].debug(T[1].rt);puts("s");
            pre=up(x-pre);  
        }
        else if(opt==3){
            scanf("%d",&x);
            pre=down(x-pre);
        //  T[1].debug(T[1].rt);puts("the");    
        //  puts("vvv");T[0].debug(T[0].rt);    
        //  puts("ggg");
        }
        else {
            scanf("%d",&x);
            pre=query(x-pre);
        }
    }
    return 0;
}
/*
10 10
1 2 11
3 13
2 5
3 7
2 8
2 10
2 11
3 14
2 18
4 9
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值