[ZJOI2006]书架

题目
平衡树裸题。。按层数随便赋个值表示相对关系,然后查找排名就好了。(我依然调一年)…

然而这题线段树做法比较有趣。
空间开足够对于每次top和bot操作要新开空间。数组记录编号为s的书在线段树上的位置。
线段树上维护那段区间有没有书。
然后对于top和bot操作。。二分一直跳到没有书的第一个为0的点。对于ins操作。交换相邻点。
ask查询区间和(前缀)。
query二分一直找到那一本书(靠区间和来找)。

然而我并没有写线段树做法。

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

const int MAXN=8e4+5;
const int INF=1e9+7;

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



struct treap{
    int rt,cnt;
    int lson[MAXN],rson[MAXN],prio[MAXN],size[MAXN],w[MAXN];
    inline void pushup(int p){size[p]=size[lson[p]]+size[rson[p]]+1;}
    inline 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);
        }
        par tem=split(r,x-size[l]-1);
        rson[p]=tem.first;pushup(p);return mp(p,tem.second);
    }
    inline 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;
    }   
    inline void newnode(int p,int x){
        lson[p]=rson[p]=0;prio[p]=rand();size[p]=1;w[p]=x;
    }
}T;

void dfs(int p){
    if(!p)return;
    dfs(T.lson[p]);
    printf("%d ",T.w[p]);
    dfs(T.rson[p]);
}

int where[MAXN],sta[MAXN],xj,sj;

int build(int n){
    int tmp,tp=0;
    for(int i=1;i<=n;i++){
        int pre=0;
        scanf("%d",&tmp);
        T.newnode(++T.cnt,tmp);
        where[tmp]=T.cnt;
        while(tp&&T.prio[sta[tp]]>T.prio[T.cnt]){
            pre=sta[tp--];T.pushup(pre);
        }
        if(tp)T.rson[sta[tp]]=T.cnt;
        T.lson[T.cnt]=pre;
        sta[++tp]=T.cnt;
    }
    while(tp)T.pushup(tp--);
    xj=1;sj=n;
    return sta[1];
}

int queryrank(int x){
    int cp=where[x],tmp=T.rt,ans=0;
//  cout<<cp<<"okokok  ";
//  cout<<T.size[T.lson[T.rt]]+1;
    while(where[T.w[tmp]]!=cp){
    //  cout<<tmp<<":"<<where[tmp]<<endl;
        if(cp>=where[T.w[tmp]])ans+=T.size[T.lson[tmp]]+1;
        else {tmp=T.lson[tmp];continue;}

        if(cp>where[T.w[tmp]])tmp=T.rson[tmp];
    }
    ans+=T.size[T.lson[tmp]]+1;
//  cout<<"  "<<T.w[tmp]<<"sasa   sasasa   sasa";cout<<ans<<endl;
    return ans;
}

void top(){
    int tmp;
    scanf("%d",&tmp);
    int a=queryrank(tmp);
    par tem1=T.split(T.rt,a);
    par tem2=T.split(tem1.first,a-1);
//  cout<<a<<"okok";
    where[T.w[tem2.second]]=--xj;
    T.rt=T.merge(T.merge(tem2.second,tem2.first),tem1.second);
//  dfs(T.rt);
}

void bot(){
    int tmp;
    scanf("%d",&tmp);
    int a=queryrank(tmp);
    par tem1=T.split(T.rt,a);
    par tem2=T.split(tem1.first,a-1);
    where[T.w[tem2.second]]=++sj;
    T.rt=T.merge(T.merge(tem2.first,tem1.second),tem2.second);  
//  dfs(T.rt);
}

void ins(){
    int tmp,tmp2;
    scanf("%d%d",&tmp,&tmp2);
    if(tmp2==0)return;
    int a=queryrank(tmp);
    if(tmp2==1){
        par tem1=T.split(T.rt,a+1);
        par tem2=T.split(tem1.first,a-1);//t2 second 2个 
        par tem3=T.split(tem2.second,1);
        swap(where[T.w[tem3.first]],where[T.w[tem3.second]]);
        T.rt=T.merge(T.merge(tem2.first,T.merge(tem3.second,tem3.first)),tem1.second);
    }
    else {
        par tem1=T.split(T.rt,a);
        par tem2=T.split(tem1.first,a-2);//t2 second 2个 
        par tem3=T.split(tem2.second,1);
        swap(where[T.w[tem3.first]],where[T.w[tem3.second]]);
        T.rt=T.merge(T.merge(tem2.first,T.merge(tem3.second,tem3.first)),tem1.second);
    }
//  dfs(T.rt);
}

void ask(){
    int tmp;
    scanf("%d",&tmp);
    printf("%d\n",queryrank(tmp)-1);
}

void query(){
    int tmp;
    scanf("%d",&tmp);
    par tem1=T.split(T.rt,tmp-1);
    par tem2=T.split(tem1.second,1);
    printf("%d\n",T.w[tem2.first]);
    T.rt=T.merge(tem1.first,T.merge(tem2.first,tem2.second));
}

int main(){
    srand(19260817);
    char tem[15];
    int n,m;
    T.cnt=0;
    scanf("%d%d",&n,&m);
    T.rt=build(n);
//  cout<<T.w[T.rt];
//  cout<<where[T.w[T.rt]];
    for(int i=1;i<=m;i++){
        scanf("%s",tem);
        if(tem[0]=='T')top();
        if(tem[0]=='B')bot();
        if(tem[0]=='I')ins();
        if(tem[0]=='A')ask();
        if(tem[0]=='Q')query();
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值