bzoj 3224: Tyvj 1728 普通平衡树

来源:互联网 发布:淘宝客推广宣传海报 编辑:程序博客网 时间:2024/06/08 17:25

3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

106465
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;}//按照二叉树性质插入xvoid 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;}





原创粉丝点击