解题: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 }

原文地址:https://www.cnblogs.com/ydnhaha/p/9971675.html

时间: 2024-10-17 08:47:24

解题:ZJOI 2006 书架的相关文章

BZOJ 1861 ZJOI 2006 Book 书架 Splay

题目大意:有一个书架,现在需要经常改变这些书的位置,每次询问一本书在哪或者第几本书是什么. 思路:赤裸裸的Splay,只是有些小事需要注意.因为他有的时候问你一个书在哪,这个事情不能只在Splay中就能解决,我们需要辅助他解决.注意到操作中没有加入书的操作,也就是书的总数并不会变化,而且Splay的过程中只是指针的变动,所以不会有点发生变化,所以在一开始建树的时候维护一个数组,表示这本书在Splay中的节点,这样我们就能快速的找到任意一本书的节点.询问一本书的排名的时候,我们需要先找到这个节点,

[BZOJ1003](ZJOI 2006) 物流运输trans

[题目描述] 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪.由于各种因素的存在,有的时候某个码头会无法装卸货物.这时候就必须修改运输路线,让货物能够按时到达目的地.但是修改路线是一件十分麻烦的事情,会带来额外的成本.因此物流公司希望能够订一个n天的运输计划,使得总成本尽可能地小. [输入格式] 第一行是四个整数n(1<=n<=100).m(1<=

[ZJOI 2006]超级麻将

Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量.ai表示数字为i的牌有ai张.(0<=ai<=100) Output 输出N行,若胡了则输出Yes,否则输出No,注意区分Yes,No的大小写! Sample Input 3 2 4 0 0 0 0 0 -- 0(一共98个0) 2 4 2 0 0 0 0 -- 0(一共97个0) 2 3 2 0 0 0 0 -- 0(一

BZOJ 1003 ZJOI 2006 物流运输 动态规划+SPFA

题目大意:有一些码头由若干条边组成,有些时候有一些码头需要维修,这个期间不能使用这个码头.跟换航线的话会有一定的花费,求规定天数内的最小花费. 思路:最短路方面用SPFA就行,关键是动态规划.这个动规我想了很久,结果到最后发现自己想复杂了.我一开始想的是用SPFA处理出每一个不同的段,然后动规.这样做不仅分段不好分,动规也不好写.之后才发现,一共天数才100,枚举起点和终点才10000,套一个SPFA的O(kn)也不到1qw... CODE: #include <queue> #include

BZOJ 1862/1056 ZJOI 2006 GameZ游戏排名系统/ HAOI 2008 排名系统 Treap (双倍经验)

题目大意:维护一种游戏排名系统,为他们的得分排序,若得分一样,则时间早的优先.有的时候要查询一个人是第几名,或者一段名次都是谁. 思路:拿到题一看就知道是暴力Treap乱搞,但是一查不知道看到了谁的文章,说Treap会T,我就战战兢兢的写了Splay,结果T了,拿到数据发现被一个点卡了100s.于是怒写Treap,1.2s怒切. PS:千万不要相信谣言.. CODE: #include <cstdio> #include <cctype> #include <cstring&

$[\ ZJOI\ 2006\ ]\ Mahjong$

\(\\\) \(Description\) 现有权值分别为\(1\text~100\)的\(100\)种牌,分别给出每种排的张数\(A_i\),试判断能否胡牌,胡牌需要将所有牌不重不漏地分成以下几类: 三张或四张相同的牌 权值连续的三张牌 两张相同的牌,这一类必须要有,而且只能有一个 一组数据共需要\(N\)次判断,胡了输出"\(Yes\)",否则输出"\(No\)". \(N\in [1,100]\),\(A_i\in [0,100]\) \(\\\) \(So

滚粗记之2016军训后学校模拟赛

2016.8.24 maths(40/100): 容斥原理 f(n)与f(n的质因数)是递推关系 //数据中的“质数”特殊点已经给了提示 所以,先预处理即可 mahjong(0/100):暴搜+hash   orzzzzzzz bzoj1860       n<=100,t<=100 所以这题时间复杂度大致为O(n^2*t) [ZJOI2006]     想到dp         //考试时想到了但不知怎么编,还是太弱了QAQ肿么办 然而暴搜QAQ 附上详解:http://blog.csdn.

NOIP 2006 解题报告

第一题: 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记.因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量.如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为(Mars单位),新产生的珠子的头标记为m,尾

解题:POI 2006 PRO-Professor Szu

题面 这个题是比较套路的做法啦,建反图后缩点+拓扑排序嘛,对于所有处在$size>=2$的SCC中的点都是无限解(可以一直绕) 然后注意统计的时候的小细节,因为无限解/大解也要输出,所以我们把这些点统一统计成36501,然后所有的方案都对36501取min就可以很方便的输出了 1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 using n