伸展树模板

来源:互联网 发布:詹姆斯深蹲力量数据 编辑:程序博客网 时间:2024/06/05 02:32

给定一个数n,代表有一个数列1~n,有下面两种操作:

  1. CUT a b c 把区间[a,b]这一段元素切下来接到新序列第c个元素的后面
  2. FLIP a b 反转区间[a,b]

最后遍历整个序列

#define key_val son[son[root][1]][0]typedef long long ll;const int N = 300010, INF = 0x3f3f3f3f, MOD = 1000000;int son[N][2], fat[N], siz[N];int key[N], val[N], lazy[N];int root, tot, cnt;int arr[N];int n, m;void new_node(int val, int fa, int &x){    x = ++tot;    fat[x] = fa, key[x] = val;    siz[x] = 1, lazy[x] = 0;    son[x][0] = son[x][1] = 0;}void push_up(int x){    siz[x] = siz[son[x][0]] + siz[son[x][1]] + 1;}void push_down(int x){    if(lazy[x])    {        swap(son[x][0], son[x][1]);        lazy[son[x][0]] ^= 1, lazy[son[x][1]] ^= 1;        lazy[x] = 0;    }}void Rotate(int x, int p){    int y = fat[x];    push_down(y); push_down(x);    son[y][!p] = son[x][p], fat[son[x][p]] = y;    if(fat[y]) son[fat[y]][son[fat[y]][1]==y] = x;    fat[x] = fat[y];    son[x][p] = y, fat[y] = x;    push_up(y);}void splay(int x, int goal){    push_down(x);    while(fat[x] != goal)    {        int y = fat[x], z = fat[y];        //在这里下传翻转标记,在rotate里下传标记可能会使树形改变导致旋转出错        push_down(z); push_down(y); push_down(x);        if(fat[y] == goal) Rotate(x, son[y][0] == x);        else        {            int p = son[fat[y]][0] == y;            if(son[y][p] == x) Rotate(x, !p), Rotate(x, p);            else Rotate(y, p), Rotate(x, p);        }    }    push_up(x);    if(goal == 0) root = x;}int get_prec(int x){    push_down(x);    x = son[x][0];    push_down(x);    while(son[x][1]) x = son[x][1], push_down(x);    return x;}int get_succ(int x){    push_down(x);    x = son[x][1];    push_down(x);    while(son[x][0]) x = son[x][0], push_down(x);    return x;}int get_kth(int k){    int x = root;    push_down(x);    while(true)    {        if(k <= siz[son[x][0]]) x = son[x][0];        else if(k > siz[son[x][0]] + 1) k -= (siz[son[x][0]] + 1), x = son[x][1];        else break;        push_down(x);    }    return x;}//int get_kth(int x, int k)//{//    push_down(x);//    if(k <= siz[son[x][0]]) return get_kth(son[x][0], k);//    else if(k > siz[son[x][0]] + 1) return get_kth(son[x][1], k - siz[son[x][0]] - 1);//    return x;//}void build(int l, int r, int fa, int &x){    if(l > r) return;    int mid = (l + r) >> 1;    new_node(mid, fa, x);    build(l, mid-1, x, son[x][0]);    build(mid+1, r, x, son[x][1]);    push_up(x);}void cut(int a, int b, int c){    splay(get_kth(a), 0);    splay(get_kth(b+2), root);    int tmp = key_val;    key_val = 0;    push_up(son[root][1]), push_up(root);    splay(get_kth(c+1), 0);    splay(get_succ(root), root);    key_val = tmp, fat[key_val] = son[root][1];    push_up(son[root][1]), push_up(root);}void rev(int a, int b){    splay(get_kth(a), 0);    splay(get_kth(b+2), root);    lazy[key_val] ^= 1;}void inorder(int x){    if(! x) return;    push_down(x);    inorder(son[x][0]);    if(key[x] > 0) printf("%d%c", key[x], ++cnt == n ? '\n' : ' ');    inorder(son[x][1]);}void init(){    root = tot = 0;    son[0][0] = son[0][1] = siz[0] = fat[0] = 0;    key[0] = val[0] = lazy[0] = 0;    new_node(-INF, 0, root);//插入两个边界值,然后把序列插入两个边界值之间    new_node(-INF, root, son[root][1]);    build(1, n, son[root][1], key_val);    push_up(son[root][1]), push_up(root);}int main(){    char op[10];    int a, b, c;    while(scanf("%d%d", &n, &m), n != -1 || m != -1)    {        init();        for(int i = 1; i <= m; i++)        {            scanf(" %s%d%d", op, &a, &b);            if(op[0] == 'C')            {                scanf("%d", &c);                cut(a, b, c);            }            else rev(a, b);        }        cnt = 0;        inorder(root);    }    return 0;}
  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求x的后继(后继定义为大于x,且最小的数)
const int N = 100000 + 10;int son[N][2], key[N], siz[N], fat[N], mul[N];int root, tot, prec, succ;void init(){    tot = root = 0;}void new_node(int val, int fa, int &x){    x = ++tot;    fat[x] = fa, key[x] = val;    siz[x] = mul[x] = 1;    son[x][0] = son[x][1] = 0;}void push_up(int x){    siz[x] = siz[son[x][0]] + siz[son[x][1]] + mul[x];}void Rotate(int x, int p){    int y = fat[x];    son[y][!p] = son[x][p], fat[son[x][p]] = y;    if(fat[y]) son[fat[y]][son[fat[y]][1]==y] = x;    fat[x] = fat[y];    son[x][p] = y, fat[y] = x;    push_up(y);}void splay(int x, int goal){    while(fat[x] != goal)    {        int y = fat[x];        if(fat[y] == goal) Rotate(x, son[y][0] == x);        else        {            int p = son[fat[y]][0] == y;            if(son[y][p] == x) Rotate(x, !p), Rotate(x, p);            else Rotate(y, p), Rotate(x, p);        }    }    push_up(x);    if(goal == 0) root = x;}void Insert(int val){    int y = 0, x = root;    while(x && key[x] != val) y = x, x = son[x][key[x]<val];    if(x) mul[x]++;    else new_node(val, y, x);    if(y) son[y][key[y]<val] = x;    splay(x, 0);}int Find(int val){    int x = root;    while(x && key[x] != val) x = son[x][key[x]<val];    return x;}int get_prec(int x){    x = son[x][0];    while(son[x][1]) x = son[x][1];    return x;}int get_succ(int x){//求x的后继    x = son[x][1];    while(son[x][0]) x = son[x][0];    return x;}void del(int val){    int x = Find(val);    if(!x) return;    splay(x, 0);    if(mul[root] > 1)    {        siz[root]--, mul[root]--; return;    }    if(!son[root][0] || !son[root][1])        root = son[root][0] + son[root][1], fat[root] = 0;    else    {        int t = get_succ(root);        splay(t, root);        son[son[root][1]][0] = son[root][0], root = son[root][1];        fat[son[root][0]] = root, fat[root] = 0;        push_up(root);    }}int get_kth(int k){    int x = root;    while(true)    {        if(k > siz[son[x][0]] + mul[x]) k -= siz[son[x][0]] + mul[x], x = son[x][1];        else if(k <= siz[son[x][0]]) x = son[x][0];        else break;    }    return x;}//int get_kth(int x, int k)//{//    if(k > siz[son[x][0]] + mul[x]) return get_kth(son[x][1], k - siz[son[x][0]] - mul[x]);//    else if(k <= siz[son[x][0]]) return get_kth(son[x][0], k);//    else return key[x];//}int get_rank(int val){//求排名很简洁    int x = Find(val);    splay(x, 0);    return siz[son[x][0]] + 1;}void get_prec(int x, int val){//查询前驱,val不一定存在与树中,如果存在于树中,那么旋转至根,就很容易求前驱了    if(x == 0) return;    if(key[x] < val)    {        prec = key[x];        get_prec(son[x][1], val);    }    else get_prec(son[x][0], val);}void get_succ(int x, int val){//与求前驱同理    if(x == 0) return;    if(key[x] > val)    {        succ = key[x];        get_succ(son[x][0], val);    }    else get_succ(son[x][1], val);}int main(){    int n, op, x;    scanf("%d", &n);    init();    while (n--)    {        scanf("%d%d", &op, &x);        if (op == 1) Insert(x);        else if (op == 2) del(x);        else if (op == 3) printf("%d\n", get_rank(x));        else if (op == 4) printf("%d\n", key[get_kth(x)]);        else if (op == 5)        {            get_prec(root, x);            printf("%d\n", prec);        }        else        {            get_succ(root, x);            printf("%d\n", succ);        }    }    return 0;}
原创粉丝点击