解题:ZJOI 2006 书架

题面

学习了如何在维护序列的平衡树上查找某个数:按初始的顺序定个权值,然后每次找那个权值的DFS序即可。具体实现就是不停往上跳,然后是父亲的右儿子就加上父亲的左儿子,剩下的就是继续熟悉无旋树堆

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=100005;
  6 int num[N],val[N],siz[N],anc[N],son[N][2],rnk[N];
  7 int n,m,w,x,y,z,rd,re,tot,pos,root; char ch[10];
  8 void Pushup(int nde)
  9 {
 10     siz[nde]=siz[son[nde][0]]+siz[son[nde][1]]+1;
 11     if(son[nde][0]) anc[son[nde][0]]=nde;
 12     if(son[nde][1]) anc[son[nde][1]]=nde;
 13 }
 14 int Create(int tsk)
 15 {
 16     siz[++tot]=1;
 17     val[tot]=tsk;
 18     num[tsk]=tot;
 19     rnk[tot]=rand();
 20     return tot;
 21 }
 22 int Merge(int x,int y)
 23 {
 24     if(!x||!y) return x+y;
 25     else if(rnk[x]<=rnk[y])
 26     {
 27         son[x][1]=Merge(son[x][1],y);
 28         Pushup(x); return x;    
 29     } 
 30     else 
 31     {
 32         son[y][0]=Merge(x,son[y][0]);
 33         Pushup(y); return y;
 34     }
 35 }
 36 void Split(int nde,int &x,int &y,int tsk)
 37 {
 38     if(!nde) x=y=0;
 39     else
 40     {
 41         if(siz[son[nde][0]]<tsk)
 42             x=nde,Split(son[nde][1],son[nde][1],y,tsk-siz[son[nde][0]]-1);
 43         else 
 44             y=nde,Split(son[nde][0],x,son[nde][0],tsk);
 45         Pushup(nde); 
 46     }
 47 }
 48 int Query(int nde)
 49 {
 50     int ret=siz[son[nde][0]]+1;
 51     while(anc[nde]) {
 52         if(nde==son[anc[nde]][1])
 53         ret+=siz[son[anc[nde]][0]]+1;
 54         nde=anc[nde];
 55     }
 56     return ret;
 57 }
 58 void DFS(int nde)
 59 {
 60     if(son[nde][0]) DFS(son[nde][0]);
 61     printf("->%d",val[nde]);
 62     if(son[nde][1]) DFS(son[nde][1]);
 63 }
 64 int main()
 65 {
 66     srand(20020513);
 67     scanf("%d%d",&n,&m);
 68     for(int i=1;i<=n;i++)
 69         scanf("%d",&rd),root=Merge(root,Create(rd));
 70     while(m--)
 71     {
 72         scanf("%s%d",ch,&rd),pos=Query(num[rd]); 
 73         if(ch[0]=='T') 
 74         {
 75             Split(root,x,z,pos),Split(x,x,y,pos-1);
 76             root=Merge(Merge(y,x),z);
 77         }
 78         else if(ch[0]=='B')
 79         {
 80             Split(root,x,z,pos),Split(x,x,y,pos-1);
 81             root=Merge(Merge(x,z),y);
 82         }
 83         else if(ch[0]=='I')
 84         {
 85             scanf("%d",&re);
 86             if(re==-1)
 87             {
 88                 Split(root,w,z,pos),Split(w,w,y,pos-1); 
 89                 Split(w,w,x,pos-2); root=Merge(Merge(Merge(w,y),x),z);
 90             }
 91             else if(re==1)
 92             {
 93                 Split(root,y,z,pos+1),Split(y,x,y,pos);
 94                 Split(x,w,x,pos-1); root=Merge(Merge(Merge(w,y),x),z);
 95             }
 96         }
 97         else if(ch[0]=='A')
 98             printf("%d\n",pos-1);
 99         else
100         {
101             Split(root,x,z,rd),Split(x,x,y,rd-1);
102             printf("%d\n",val[y]); 
103             root=Merge(Merge(x,y),z);
104         }
105     }
106     return 0;
107 }
View Code

 

转载于:https://www.cnblogs.com/ydnhaha/p/9971675.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值