Description
H国是一个热爱写代码的国家,那里的人们很小去学校学习写各种各样的数据结构。伸展树(splay)是一种数据结构,因为代码好写,功能多,效率高,掌握这种数据结构成为了H国的必修技能。有一天,邪恶的“卡”带着他的邪恶的“常数”来企图毁灭H国。“卡”给H国的人洗脑说,splay如果写成单旋的,将会更快。“卡”称“单旋splay”为“spaly”。虽说他说的很没道理,但还是有H国的人相信了,小H就是其中之一,spaly马上成为他的信仰。而H国的国王,自然不允许这样的风气蔓延,国王构造了一组数据,数据由m(不超过10^5)个操作构成,他知道这样的数据肯定打垮spaly,但是国王还有很多很多其他的事情要做,所以统计每个操作所需要的实际代价的任务就交给你啦。数据中的操作分为5种:
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
输入文件名为splay.in。
第一行单独一个正整数m (1 <= m <= 10^5)。
接下来m行,每行描述一个操作:首先是一个操作编号c(1<=c<=5),既问题描述中给出的5种操作中的编号,若c= 1,则再输入一个非负整数key,表示新插入节点的关键码。
Output
输出文件名为splay.out。
输出共m行,每行一个整数,第i行对应第i个输入的操作的代价。
Sample Input
5
1 2
1 1
1 3
4
5
Sample Output
1
2
2
2
2
Data Constraint
20%的数据满足:1 <= m <= 1000。
另外30%的数据满足:不存在4,5操作。
100%的数据满足:1<=m<=10^5;1<=key<=10^9。所有出现的关键码互不相同。任何一个非插入操作,一定保证树非空。在未执行任何操作之前,树为空。
分析
考虑一次插入了x,x的前驱为pre,后继为nxt,平衡树中排名相邻的两个点一定互为祖先关系,那么如果pre为nxt的祖先,x就插入到了nxt的左儿子,如果nxt为pre的祖先,x就插入到了pre的右儿子
考虑把最小值旋到根的操作,最小值没有左子树,最小值的右子树变成了最小值父亲的左子树,根变成了最小值的右儿子
把最大值旋到根同理
我很好奇 为什么我JZOJ上A了,放到BZOJ上却T了//
代码
#include <bits/stdc++.h>
#define N 1000005
using namespace std;
struct NOTE
{
int son[2];
int fa;
}t[N];
int root,size;
struct NODE
{
int l,r;
int dep;
int lazy;
}T[N * 2];
int n,m;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void build(int p,int l,int r)
{
T[p].l = l;
T[p].r = r;
if (l == r)
return;
int mid = (l + r) >> 1;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
}
int pos[N];
int find(int x)
{
int l = 1, r = n,now;
while (l <= r)
{
int mid = (l + r) >> 1;
if (pos[mid] >= x)
now = mid, r = mid - 1;
else l = mid + 1;
}
return now;
}
void pushDown(int p)
{
T[p * 2].lazy += T[p].lazy;
T[p * 2 + 1].lazy += T[p].lazy;
T[p * 2].dep += T[p].lazy;
T[p * 2 + 1].dep += T[p].lazy;
T[p].lazy = 0;
}
void change(int p,int x,int y)
{
if (T[p].l == T[p].r)
{
T[p].dep = y;
return;
}
if (T[p].lazy)
pushDown(p);
int mid = (T[p].l + T[p].r) >> 1;
if (x <= mid)
change(p * 2, x, y);
else change(p * 2 + 1, x, y);
}
int query(int p,int x)
{
if (!x)
return 0;
if (T[p].l == T[p].r)
return T[p].dep;
int mid = (T[p].l + T[p].r) >> 1;
if (T[p].lazy)
pushDown(p);
if (x <= mid)
query(p * 2,x);
else query(p * 2 + 1,x);
}
void changeQ(int p,int l,int r,int x)
{
if (l > r)
return;
if (l == T[p].l && r == T[p].r)
{
T[p].dep += x;
T[p].lazy += x;
return;
}
if (T[p].lazy)
pushDown(p);
int mid = (T[p].l + T[p].r) >> 1;
if (r <= mid)
changeQ(p * 2,l,r,x);
else
if (l > mid)
changeQ(p * 2 + 1,l,r,x);
else
{
changeQ(p * 2,l,mid,x);
changeQ(p * 2 + 1, mid + 1, r, x);
}
}
void rotate(int x, int &k)
{
int y = t[x].fa;
int z = t[y].fa;
int l,r;
if (t[y].son[0] == x)
l = 0;
else l = 1;
r = l ^ 1;
if (y == k)
k = x;
else
{
if (t[z].son[0] == y)
t[z].son[0] = x;
else t[z].son[1] = x;
}
t[x].fa = z;
t[y].fa = x;
t[t[x].son[r]].fa = y;
t[y].son[l] = t[x].son[r];
t[x].son[r] = y;
}
void splay(int x,int &k)
{
while (x != k)
{
int y = t[x].fa;
int z = t[y].fa;
if (y != k)
{
if (t[z].son[0] == y ^ t[y].son[0] == x)
rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
int getMin()
{
int y = root;
while (t[y].son[0])
y = t[y].son[0];
return y;
}
int getMax()
{
int y = root;
while (t[y].son[1])
y = t[y].son[1];
return y;
}
int Pre;
void getPre(int x,int k)
{
if (!k)
return;
if (k < x)
{
Pre = k;
getPre(x,t[k].son[1]);
}
else getPre(x,t[k].son[0]);
}
int Next;
void getNext(int x,int k)
{
if (!k)
return;
if (k > x)
{
Next = k;
getNext(x,t[k].son[0]);
}
else getNext(x,t[k].son[1]);
}
struct NODET
{
int son[2];
int fa;
}tr[N];
int trroot;
void insert(int x,int &k,int last)
{
if (!k)
{
Pre = 0;
Next = 0;
k = x;
t[x].fa = last;
if (x < last)
{
Next = last;
getPre(x,root);
}
else
{
Pre = last;
getNext(x,root);
}
int dep1 = query(1,Next);
int dep2 = query(1,Pre);
if (dep1 > dep2)
{
tr[x].fa = Next;
tr[Next].son[0] = x;
}
else
{
tr[x].fa = Pre;
tr[Pre].son[1] = x;
}
printf("%d\n",max(dep1,dep2) + 1);
change(1,x,max(dep1,dep2) + 1);
splay(x,root);
return;
}
if (x < k)
insert(x,t[k].son[0],k);
else insert(x,t[k].son[1],k);
}
void sloveMin()
{
int x = getMin();
printf("%d\n",query(1,x));
int k = trroot;
int y = tr[x].fa;
int z = tr[x].son[1];
if (k == x)
return;
if (y)
changeQ(1,y,n,1);
change(1,x,1);
tr[y].son[0] = z;
tr[z].fa = y;
tr[x].fa = 0;
tr[x].son[1] = k;
tr[k].fa = x;
trroot = x;
splay(x,root);
}
void sloveMax()
{
int x = getMax();
printf("%d\n",query(1,x));
int k = trroot;
int y = tr[x].fa;
int z = tr[x].son[0];
if (k == x)
return;
if (y)
changeQ(1,1,y,1);
change(1,x,1);
tr[y].son[1] = z;
tr[z].fa = y;
tr[x].fa = 0;
tr[x].son[0] = k;
tr[k].fa = x;
trroot = x;
splay(x,root);
}
void doMin()
{
int x = getMin();
printf("%d\n",query(1,x));
int y = tr[x].fa;
int z = tr[x].son[1];
if (y)
changeQ(1, x + 1, y - 1, -1);
else
{
trroot = z;
if (z)
changeQ(1, x + 1, n, - 1);
}
tr[z].fa = y;
tr[x].son[1] = 0;
tr[y].son[0] = z;
splay(x,root);
root = t[x].son[1];
t[x].son[1] = t[t[x].son[1]].fa = 0;
}
void doMax()
{
int x = getMax();
printf("%d\n",query(1,x));
int y = tr[x].fa;
int z = tr[x].son[0];
if (y)
changeQ(1, y + 1, x - 1, -1);
else
{
trroot = z;
if (z)
changeQ(1, 1, x - 1, -1);
}
tr[z].fa = y;
tr[x].son[0] = 0;
tr[y].son[1] = z;
splay(x,root);
root = t[x].son[0];
t[x].son[0] = t[t[x].son[0]].fa = 0;
}
int opt[N];
int num[N];
int main()
{
freopen("splay.in","r",stdin);
freopen("splay.out","w",stdout);
m = read();
for (int i = 1; i <= m; i++)
{
opt[i] = read();
if (opt[i] == 1)
pos[++n] = num[i] = read();
}
sort(pos + 1,pos + n + 1);
for (int i = 1; i <= m; i++)
{
if (opt[i] == 1)
num[i] = find(num[i]);
}
build(1,1,n);
int tot = 0;
for (int i = 1; i <= m; i++)
{
if (opt[i] == 1)
{
insert(num[i], root, 0);
tot++;
if (tot == 1)
trroot = num[i];
}
if (opt[i] == 2)
sloveMin();
if (opt[i] == 3)
sloveMax();
if (opt[i] == 4)
doMin(), tot--;
if (opt[i] == 5)
doMax(), tot--;
}
}