[BZOJ4825][HNOI2017]单旋(线段树+Splay)

4825: [Hnoi2017]单旋

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 667  Solved: 342
[Submit][Status][Discuss]

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

HINT

 

Source

代码用时:2h

感觉代码难度很低啊为什么我还是花了很长时间。。

思维比较简单,只要把三种操作想清楚了就差不多了。

比较自然的想法应该是Splay,但线段树实现复杂度和常数都更优。

线段树做法网上好像只找到一个(而且没有标记永久化的代码并不是很优美常数也稍大)

这里有一个自认为比较优的做法。

(本题线段树做法的思想还是有点巧妙的,利用了题目只单旋最值的设定)

12140KB,1108ms 

 1 #include<set>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<iostream>
 5 #define rep(i,l,r) for (int i=l; i<=r; i++)
 6 using namespace std;
 7 
 8 template<typename T>inline void rd(T &x){
 9     int t; char ch;
10     for (t=0; !isdigit(ch=getchar()); t=(ch=='-'));
11     for (x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
12     if (t) x=-x;
13 }
14 
15 const int N=200100;
16 int m,tot,d,rt,D[N<<2],rs[N],ls[N],fa[N],a[N],b[N],op[N][2];
17 set<int>S;
18 set<int>::iterator it,sub,pro;
19 
20 void mdf(int x,int L,int R,int l,int r,int k){
21     if (L==l && R==r){ D[x]+=k; return; }
22     int mid=(L+R)>>1;
23     if (r<=mid) mdf(x<<1,L,mid,l,r,k);
24     else if (l>mid) mdf((x<<1)|1,mid+1,R,l,r,k);
25         else mdf(x<<1,L,mid,l,mid,k),mdf((x<<1)|1,mid+1,R,mid+1,r,k);
26 }
27 
28 int que(int x,int L,int R,int k){
29     if (L==R) return D[x];
30     int mid=(L+R)>>1;
31     if (k<=mid) return D[x]+que(x<<1,L,mid,k);
32         else return D[x]+que((x<<1)|1,mid+1,R,k);
33 }
34 
35 int main(){
36     freopen("bzoj4825.in","r",stdin);
37     freopen("bzoj4825.out","w",stdout);
38     rd(m);
39     rep(i,1,m){
40         rd(op[i][0]); if (op[i][0]==1) rd(op[i][1]);
41         if (op[i][0]==1) b[++tot]=op[i][1];
42     }
43     sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1;
44    rep(i,1,m) if (op[i][0]==1) a[i]=lower_bound(b+1,b+tot+1,op[i][1])-b;
45     rep(i,1,m){
46         if (op[i][0]==1){
47             if (S.empty()) rt=a[i],d=1;
48             else{
49                 it=S.upper_bound(a[i]),sub=it;
50                 if (sub==S.begin()) ls[*sub]=a[i],fa[a[i]]=*sub,d=que(1,1,tot,*sub)+1;
51                 else{
52                     pro=--it;
53                     if (sub==S.end()) rs[*pro]=a[i],fa[a[i]]=*pro,d=que(1,1,tot,*pro)+1;
54                     else if (que(1,1,tot,*sub)<que(1,1,tot,*pro))
55                      rs[*pro]=a[i],fa[a[i]]=*pro,d=que(1,1,tot,*pro)+1;
56                         else ls[*sub]=a[i],fa[a[i]]=*sub,d=que(1,1,tot,*sub)+1;
57                 }
58             }
59             printf("%d\n",d); mdf(1,1,tot,a[i],a[i],d-que(1,1,tot,a[i]));
60          S.insert(a[i]);
61         }
62         if (op[i][0]==2 || op[i][0]==4){
63             it=S.begin(); d=que(1,1,tot,*it); printf("%d\n",d);
64             if ((*it)!=rt){
65                 mdf(1,1,tot,1,tot,1); mdf(1,1,tot,*it,*it,-d);
66                 int t=fa[*it]; ls[t]=fa[*it]=0;
67                 if (rs[*it]){
68                     mdf(1,1,tot,(*it)+1,t-1,-1);
69                fa[rs[*it]]=t; ls[t]=rs[*it];
70                 }
71             rs[*it]=rt; fa[rt]=*it; rt=*it;
72             }
73             if (op[i][0]==4) rt=rs[*it],rs[*it]=fa[rt]=0,mdf(1,1,tot,1,tot,-1),S.erase(*it);
74         }
75         if (op[i][0]==3 || op[i][0]==5){
76             it=S.end(); it--; d=que(1,1,tot,*it); printf("%d\n",d);
77             if ((*it)!=rt){
78                 mdf(1,1,tot,1,tot,1); mdf(1,1,tot,*it,*it,-d);
79                 int t=fa[*it]; rs[t]=fa[*it]=0;
80                 if (ls[*it]){
81                     mdf(1,1,tot,t+1,(*it)-1,-1);
82                fa[ls[*it]]=t; rs[t]=ls[*it];
83                 }
84             ls[*it]=rt; fa[rt]=*it; rt=*it;
85             }
86             if (op[i][0]==5) rt=ls[*it],ls[*it]=fa[rt]=0,mdf(1,1,tot,1,tot,-1),S.erase(*it);
87         }
88     }
89     return 0;
90 }

 

 惊了,splay跑的比线段树还快。

5752KB,900ms

代码用时:1h

一开始想自己写出来,思路并不复杂但代码很繁琐(模板占了大部分但想敲对并不容易)。

看了网上的代码抄了一份下来竟然1A,可能是我抄代码的经历中最顺利的一次吧。

但抄来的代码终究不是自己的,要勇于写这种代码稍长的题目,后面还会有比这长的多的题!

 

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #define ls c[x][0]
  5 #define rs c[x][1]
  6 #define rep(i,l,r) for (int i=l; i<=r; i++)
  7 using namespace std;
  8 
  9 template<typename T>inline void rd(T &x){
 10    int t; char ch;
 11    for (t=0; !isdigit(ch=getchar()); t=(ch=='-'));
 12    for (x=ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
 13    if (t) x=-x;
 14 }
 15 
 16 const int inf=2000000000,N=100100;
 17 int n,cnt,rt,Q,fa[N],v[N],sz[N],c[N][2],s[N],dep[N],mn[N];
 18 
 19 void push(int x){
 20    v[ls]+=v[x]; dep[ls]+=v[x]; mn[ls]+=v[x];
 21    v[rs]+=v[x]; dep[rs]+=v[x]; mn[rs]+=v[x];
 22    v[x]=0;
 23 }
 24 
 25 void upd(int x){
 26    sz[x]=sz[ls]+sz[rs]+1; mn[x]=dep[x];
 27    if (ls) mn[x]=min(mn[x],mn[ls]);
 28    if (rs) mn[x]=min(mn[x],mn[rs]);
 29 }
 30 
 31 void rot(int &rt,int x){
 32    int y=fa[x],z=fa[y],w=(c[y][1]==x);
 33    if (y==rt) rt=x; else c[z][c[z][1]==y]=x;
 34    fa[x]=z; fa[y]=x; fa[c[x][w^1]]=y;
 35    c[y][w]=c[x][w^1]; c[x][w^1]=y; upd(y);
 36 }
 37 
 38 void splay(int &rt,int x){
 39    while (x!=rt) {
 40       int y=fa[x],z=fa[y];
 41       if (y!=rt){
 42          if ((c[z][1]==y)^(c[y][1]==x)) rot(rt,x); else rot(rt,y);
 43       }
 44       rot(rt,x);
 45    }
 46    upd(x);
 47 }
 48 
 49 void ins(int &x,int S,int d,int lst){
 50    if (!x){
 51       x=++cnt, s[cnt]=S; dep[cnt]=mn[cnt]=d;
 52       sz[cnt]=1; fa[cnt]=lst; return;
 53    }
 54    ins(c[x][S>s[x]],S,d,x); upd(x);
 55 }
 56 
 57 int getpre(int x,int S){
 58    if (!x) return 0;
 59    if (v[x]) push(x);
 60    if (s[x]>S) return getpre(c[x][0],S);
 61    Q=getpre(c[x][1],S);
 62    if (Q) return Q; else return x;
 63 }
 64 
 65 int getnxt(int x,int S){
 66    if (!x) return 0;
 67    if (v[x]) push(x);
 68    if (s[x]<S) return getnxt(rs,S);
 69    Q=getnxt(ls,S);
 70    if (Q) return Q; else return x;
 71 }
 72 
 73 int find(int x,int k){
 74    if (v[x]) push(x);
 75    if (sz[ls]+1==k) return x;
 76    if (sz[ls]+1<k) return find(rs,k-sz[ls]-1);
 77    return find(ls,k);
 78 }
 79 
 80 int getl(int x,int d){
 81    if (!x) return 0;
 82    if (v[x]) push(x);
 83    if (min(mn[ls],dep[x])>=d) return getl(rs,d)+sz[ls]+1;
 84       else return getl(ls,d);
 85 }
 86 
 87 int getr(int x,int d){
 88    if (!x) return 0;
 89    if (v[x]) push(x);
 90    if (min(mn[rs],dep[x])>=d) return getr(ls,d)+sz[rs]+1;
 91       else return getr(rs,d);
 92 }
 93 
 94 int split(int l,int r){
 95    int t1=find(rt,l-1),t2=find(rt,r+1);
 96    splay(rt,t1); splay(c[rt][1],t2); return c[c[rt][1]][0];
 97 }
 98 
 99 void mdf(int l,int r,int ad){
100    int y=split(l,r); v[y]+=ad; mn[y]+=ad; dep[y]+=ad;
101 }
102 
103 void change(int x,int S){
104    if (v[x]) push(x);
105    if (s[x]==S) dep[x]=1; else change(c[x][S>s[x]],S);
106    upd(x);
107 }
108 
109 int main(){
110    freopen("bzoj4825.in","r",stdin);
111    freopen("bzoj4825.out","w",stdout);
112    rd(n); ins(rt,-inf,inf,0); ins(rt,inf,inf,0); mn[0]=inf;
113    rep(i,1,n){
114       int op,x; rd(op);
115       if (op==1){
116          rd(x); int t1=getpre(rt,x),t2=getnxt(rt,x);
117          int D=max(t1>2 ? dep[t1] : 0,t2>2 ? dep[t2] : 0)+1;
118          ins(rt,x,D,0); splay(rt,cnt); printf("%d\n",D);
119       }
120       if (!(op&1)){
121          int x=find(rt,2),y=min(getl(rt,dep[x]),sz[rt]-1)-1;
122          printf("%d\n",dep[x]); mdf(2,sz[rt]-1,1);
123          if (y>1) mdf(2,y+1,-1);
124          change(rt,s[x]);
125       }
126       if ((op&1)&&(op>1)){
127          int x=find(rt,sz[rt]-1),y=min(getr(rt,dep[x]),sz[rt]-1)-1;
128          printf("%d\n",dep[x]); mdf(2,sz[rt]-1,1);
129          if (y>1) mdf(sz[rt]-y,sz[rt]-1,-1);
130          change(rt,s[x]);
131       }
132       if (op>=4){
133          if (op==4) splay(rt,find(rt,2));
134                else splay(rt,find(rt,sz[rt]-1));
135          int l=(op==5),r=l^1,y=c[rt][l];
136          c[y][r]=c[rt][r]; fa[y]=0; fa[c[rt][r]]=y; rt=y;
137          v[rt]-=1; upd(rt);
138       }
139    }
140    return 0;
141 }

 

posted @ 2018-01-16 22:51  HocRiser  阅读(354)  评论(0编辑  收藏  举报