bzoj P4825 [Hnoi2017]单旋——solution

Description

H 国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构。伸展树(splay)是一种数据
结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了 H 国的必修技能。有一天,邪恶的“卡”带着
他的邪恶的“常数”来企图毁灭 H 国。“卡”给 H 国的人洗脑说,splay 如果写成单旋的,将会更快。“卡”称
“单旋 splay”为“spaly”。虽说他说的很没道理,但还是有 H 国的人相信了,小 H 就是其中之一,spaly 马
上成为他的信仰。 而 H 国的国王,自然不允许这样的风气蔓延,国王构造了一组数据,数据由 m 个操作构成,
他知道这样的数据肯定打垮 spaly,但是国王还有很多很多其他的事情要做,所以统计每个操作所需要的实际代价
的任务就交给你啦。
 
数据中的操作分为五种:
 
1. 插入操作:向当前非空 spaly 中插入一个关键码为 key 的新孤立节点。插入方法为,先让 key 和根比较,如果 
key 比根小,则往左子树走,否则往右子树走,如此反复,直到某个时刻,key 比当前子树根 x 小,而 x 的左子
树为空,那就让 key 成为 x 的左孩子; 或者 key 比当前子树根 x 大,而 x 的右子树为空,那就让 key 成为 
x 的右孩子。该操作的代价为:插入后,key 的深度。特别地,若树为空,则直接让新节点成为一个单个节点的树
。(各节点关键码互不相等。对于“深度”的解释见末尾对 spaly 的描述)。
2. 单旋最小值:将 spaly 中关键码最小的元素 xmin 单旋到根。操作代价为:单旋前 xmin 的深度。
(对于单旋操作的解释见末尾对 spaly 的描述)。
3. 单旋最大值:将 spaly 中关键码最大的元素 xmax 单旋到根。操作代价为:单旋前 xmax 的深度。
4. 单旋删除最小值:先执行 2 号操作,然后把根删除。由于 2 号操作之后,根没有左子树,所以直接切断根和右子
树的联系即可(具体见样例解释)。 操作代价同 2 号操 作。
5. 单旋删除最大值:先执行 3 号操作,然后把根删除。 操作代价同 3 号操作。
 
对于不是 H 国的人,你可能需要了解一些 spaly 的知识,才能完成国王的任务:
 
a. spaly 是一棵二叉树,满足对于任意一个节点 x,它如果有左孩子 lx,那么 lx 的关键码小于 x 的关键码。
如果有右孩子 rx,那么 rx 的关键码大于 x 的关键码。
b. 一个节点在 spaly 的深度定义为:从根节点到该节点的路径上一共有多少个节点(包括自己)。
c. 单旋操作是对于一棵树上的节点 x 来说的。一开始,设 f 为 x 在树上的父亲。如果 x 为 f 的左孩子,那么
执行 zig(x) 操作(如上图中,左边的树经过 zig(x) 变为了右边的树),否则执行 zag(x) 操作(在上图中,将
右边的树经过 zag(f) 就变成了左边的树)。每当执 行一次 zig(x) 或者 zag(x),x 的深度减小 1,如此反复,
直到 x 为根。总之,单旋 x 就是通过反复执行 zig 和 zag 将 x 变为根。

Input

第一行单独一个正整数 m。
接下来 m 行,每行描述一个操作:首先是一个操作编号 c∈[1,5],即问题描述中给出的五种操作中的编号,若 c
 = 1,则再输入一个非负整数 key,表示新插入节点的关键码。
1≤m≤10^5,1≤key≤10^9
所有出现的关键码互不相同。任何一个非插入操作,一定保证树非空。在未执行任何操作之前,树为空

Output

输出共 m 行,每行一个整数,第 i 行对应第 i 个输入的操作的代价。

Sample Input

5
1 2
1 1
1 3
4
5

Sample Output

1
2
2
2
2
                          ——by bzoj
http://www.lydsy.com/JudgeOnline/problem.php?id=4825


这个bzoj的蓝底好赞啊
 
如果是双旋splay,就是模板题;
然而是单旋splay,
直接模拟?
亲测洛谷t成暴力分(废话,本来就是暴力)
可能出题人刻意卡了,也可能本来就非常好卡
 
考虑尝试其他方法;
 
-操作1 k:      找到k的前驱,后继,如果当前树上前驱无右子节点,则k代表的点挂在前驱右子节点的位置,否则挂在后继的左子节点处
      可以证明前驱的右子节点与后继的左子节点至少有一个不存在;
(因为在k加入集合之前,集合中不存在大小在k的前驱和后继间的元素,于是若k的前驱有右子树,则k的后继必在此子树上)
(否则这棵子树上的所有点都在k的前驱后继之间)
(既然k的后继在k的前驱的右子树上,那么他的左子树上所有元素都在k的前驱后继之间,于是他没有左子节点)
-操作2和3:   观察单旋最小值或最大值的过程,发现此过程对树的结构影响极少,
      只是把这个代表最大|小值的节点剥离树,
      他的子节点接替他做父节点的子节点(他只有一个子节点),
      然后把剩余整个树挂在他的左|右子树位置,
-操作4和5:   相当于操作2和3省去最后一个过程,然后保留剩下的树,而把剥离的点弃置
 
维护树的结构的部分可以直接用LCT;
查找加入节点的位置——即找前驱后继可以直接用MAP实现
代码:
(又一次证明了我的代码能力和STL能力有多烂)
(LCT的写法有点奇怪……不支持换根的写法)
  1 #include<map>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 map<int ,int > MAP;
  7 int m,top;
  8 struct DT{
  9     int ch[2],CH[2],fa,FA;
 10     int size,num;
 11 };
 12 struct Splay{
 13     DT data[100010];
 14     void splay(int x){
 15         int fa,fafa;
 16         for(fa=data[x].fa;che(x);roll(x),fa=data[x].fa){
 17             fafa=data[fa].fa;
 18             if(che(fa)){
 19                 if((data[fa].ch[1]==x)^(data[fafa].ch[1]==fa))
 20                     roll(x);
 21                 else
 22                     roll(fa);
 23             }
 24         }
 25     }
 26     void roll(int x){
 27         int fa=data[x].fa,fafa=data[fa].fa,wh=data[fa].ch[1]==x;
 28         data[fa].ch[wh]=data[x].ch[wh^1],data[data[fa].ch[wh]].fa=fa;
 29         data[fa].fa=x,data[x].ch[wh^1]=fa;
 30         data[x].fa=fafa;
 31         if(data[fafa].ch[0]==fa||data[fafa].ch[1]==fa)
 32             data[fafa].ch[data[fafa].ch[1]==fa]=x;
 33         up(fa),up(x);
 34     }
 35     bool che(int x){
 36         return data[data[x].fa].ch[0]==x||data[data[x].fa].ch[1]==x;
 37     }
 38     void up(int x){
 39         data[x].size=data[data[x].ch[0]].size+data[data[x].ch[1]].size+1;
 40     }
 41 };
 42 struct LCT{
 43     Splay T;
 44     int root;
 45     void Mak_data(int id,int num){
 46         T.data[id].ch[0]=T.data[id].ch[1]=T.data[id].CH[0]=T.data[id].CH[1]=0;
 47         T.data[id].FA=T.data[id].fa=0;
 48         T.data[id].size=1,T.data[id].num=num;
 49     }
 50     void Link(int fa,int son,int wh){
 51         Access(son),T.splay(son);
 52         T.data[son].FA=fa;
 53         T.data[son].fa=fa;
 54         T.data[fa].CH[wh]=son;
 55         Access(son);
 56     }
 57     void Cut(int fa,int son){
 58         Access(fa),T.splay(son);
 59         T.data[son].FA=T.data[son].fa=0;
 60         T.data[fa].CH[T.data[fa].CH[1]==son]=0;
 61     }
 62     void Access(int x){
 63         int y=0;
 64         while(x){
 65             T.splay(x);
 66             T.data[x].ch[1]=y,T.up(x);
 67             y=x,x=T.data[x].fa;
 68         }
 69     }
 70 };
 71 LCT lct;
 72 inline void in(int &ans)
 73 {
 74     ans=0;bool p=false;char ch=getchar();
 75     while((ch>'9' || ch<'0')&&ch!='-') ch=getchar();
 76     if(ch=='-') p=true,ch=getchar();
 77     while(ch<='9'&&ch>='0') ans=ans*10+ch-'0',ch=getchar();
 78     if(p) ans=-ans;
 79 }
 80 int main()
 81 {
 82     int i,j,k,templ,tempr,temp,f,c;
 83     map<int ,int >::iterator iter;
 84     in(m);
 85     lct.root=0;
 86     for(i=1;i<=m;i++){
 87         in(j);
 88         if(j==1){
 89             in(k);
 90             lct.Mak_data(++top,k);
 91             if(lct.root){
 92                 iter=MAP.upper_bound(k);
 93                 tempr=iter->second,templ=0;
 94                 if(iter!=MAP.begin())iter--,templ=iter->second;
 95                 if(templ&&!lct.T.data[templ].CH[1])
 96                     lct.Link(templ,top,1);
 97                 else
 98                     lct.Link(tempr,top,0);
 99             }
100             else
101                 lct.root=top;
102             lct.Access(top),lct.T.splay(top);
103             printf("%d\n",lct.T.data[top].size);
104             MAP[k]=top;
105         }
106         else{
107             iter=MAP.end(),iter--;
108             if(j&1)
109                 temp=iter->second;
110             else
111                 temp=MAP.begin()->second;
112             lct.Access(temp),lct.T.splay(temp);
113             printf("%d\n",lct.T.data[temp].size);
114             if(lct.T.data[temp].FA&&lct.T.data[temp].CH[!(j&1)]){
115                 f=lct.T.data[temp].FA,c=lct.T.data[temp].CH[!(j&1)];
116                 lct.Cut(temp,c),lct.Cut(f,temp);
117                 lct.Link(f,c,j&1);
118             }
119             else{
120                 if(lct.T.data[temp].FA||lct.T.data[temp].CH[!(j&1)])
121                     if(lct.T.data[temp].FA)
122                         lct.Cut(lct.T.data[temp].FA,temp);
123                     else
124                         lct.root=lct.T.data[temp].CH[!(j&1)],lct.Cut(temp,lct.T.data[temp].CH[!(j&1)]);
125                 else{
126                     if(j>3)
127                         lct.root=0,MAP.erase(lct.T.data[temp].num);
128                     continue;
129                 }
130             }
131             if(j<4)
132                 lct.Link(temp,lct.root,!(j&1)),lct.root=temp;
133             else
134                 MAP.erase(lct.T.data[temp].num);
135         }
136     }
137 }

 

posted @ 2018-02-07 18:58  F.W.Nietzsche  阅读(192)  评论(0编辑  收藏  举报