3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 15580 Solved: 6786
[ Submit][ Status][ Discuss]
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
这个题是维护所有数是有序的, 每个rt其实就是这个数的大小所在位置,每个rt左面都比他小, 右面都比他大, 有相同的,他会缩到一个节点, cnt代表这个值的个数。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int INF = 1e9;
int n, m;
int ch[maxn][2]; //0做孩子, 1右孩子
int f[maxn]; //每个节点的父亲
int sz[maxn]; //每个节点为根子树的大小
int val[maxn]; //这个节点所表示的值
int cnt[maxn]; //这个节点所表示值的数量
int mi[maxn]; //这个节点子树的最小值
int rev[maxn]; //反转标记
int lazy[maxn]; //延迟标记
int root; // splay的根
int tot; //树所有的节点数量
void newnode(int rt, int v, int fa)
{
f[rt] = fa;
val[rt] = v;
sz[rt] = cnt[rt] = 1;
ch[rt][0] = ch[rt][1] = 0;
}
void delnode(int &rt) //删除之后, 把相关信息抹掉
{
f[rt] = val[rt] = sz[rt] = cnt[rt] = 0;
ch[rt][0] = ch[rt][1] = rt = 0;
}
void pushup(int x)
{
if(x)
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x]; //计算这个节点为根子树的节点个数
}
//void pushdown(int x)
//{
//
//}
void Rotate(int x, int k) // k = 0左旋, k = 1右旋
{
int y = f[x];int z = f[y];
// pushdown(y); pushdown(x);
ch[y][!k] = ch[x][k];
if(ch[x][k]) f[ch[x][k]] = y;
f[x] = z;
if(z) ch[z][ch[z][1]==y] = x;
f[y] = x; ch[x][k] = y;
pushup(y), pushup(x);
}
void splay(int x, int goal)
{
// pushdown(x);
while(f[x] != goal)
{
int y = f[x];
//在这里下传翻转标记,在rotate里下传标记可能会使树形改变导致旋转出错
// pushdown(z); pushdown(y); pushdown(x);
if(f[y] == goal) Rotate(x, ch[y][0] == x);
else
{
int p = ch[f[y]][0] == y;
if(ch[y][p] == x) Rotate(x, !p), Rotate(x, p);
else Rotate(y, p), Rotate(x, p);
}
}
pushup(x);
if(goal == 0) root = x;
}
//以x为根的子树 的极值点 0 极小 1 极大
int extreme(int x,int k)
{
while(ch[x][k]) x = ch[x][k];
splay(x, 0);
return x;
}
//以x为根的子树 第k个数的位置
int kth(int x, int k)
{
// pushdown(x);
if(sz[ch[x][0]]+1 <= k && k <= sz[ch[x][0]]+cnt[x]) return x;
else if(sz[ch[x][0]] >= k) return kth(ch[x][0], k);
else return kth(ch[x][1], k-sz[ch[x][0]]-cnt[x]);
}
//查找
int Search(int rt, int x)
{
// cout << rt << endl;
if(ch[rt][0] && val[rt] > x) return Search(ch[rt][0], x);
else if(ch[rt][1] && val[rt] < x) return Search(ch[rt][1], x);
return rt;
}
//前驱:小于x的最大的数
int prec(int x)
{
int k = Search(root, x);
splay(k, 0);
if(val[k] < x) return k;
return extreme(ch[k][0], 1);
}
//后继:大于x的最小的数
int sufc(int x)
{
int k = Search(root, x);
splay(k, 0);
if(val[k] > x) return k;
return extreme(ch[k][1], 0);
}
//
int Rank(int x)
{
int k = Search(root, x);
splay(k, 0);
return sz[ch[root][0]]+1;
}
//按照二叉树性质插入x
void Insert(int x)
{
int y = Search(root, x), k = -1;
if(val[y] == x)
{
cnt[y]++;
sz[y]++;
for(int yy = y; yy; yy = f[yy]) pushup(yy);
}
else
{
int p = prec(x), s = sufc(x);
splay(p, 0); splay(s, p);
newnode(++tot, x, ch[root][1]);
ch[ch[root][1]][0] = tot;
for(int z = ch[root][1]; z; z = f[z]) pushup(z);
}
splay(y, 0);
}
void Delete(int x) //删除值为x的数
{
// cout << 1 <<endl;
int y = Search(root, x);
if(val[y] != x) return ;
if(cnt[y] > 1) //因为一个一个删
{
cnt[y]--;
sz[y]--;
for(int yy = y; yy; yy = f[yy]) pushup(yy);
}
else if(ch[y][0] == 0 || ch[y][1] == 0)
{
int z = f[y];
ch[z][ch[z][1]==y] = ch[y][ch[y][0]==0];
f[ch[y][ch[y][0]==0]] = z; delnode(y);
for(int yy = z; yy; yy = f[yy]) pushup(yy);
}
else
{
int p = prec(x), s = sufc(x);
splay(p, 0); splay(s, p);
ch[ch[root][1]][0] = 0;
delnode(ch[ch[root][1]][0]);
for(int yy = s; yy; yy = f[yy]) pushup(yy);
}
}
void init()
{
root = 1;
tot = 0;
newnode(++tot, -INF, 0);
newnode(++tot, INF, root);
ch[root][1] = tot;
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int op, x ; n--;)
{
scanf("%d", &op);
scanf("%d", &x);
if(op == 1) Insert(x);
else if(op == 2) Delete(x);
else if(op == 3) printf("%d\n", Rank(x)-1);
else if(op == 4) printf("%d\n", val[kth(root, x+1)]);
else if(op == 5) printf("%d\n", val[prec(x)]);
else printf("%d\n", val[sufc(x)]);
}
}
return 0;
}