伸展树模板

给定一个数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]if(x) mul[x]++;
    else new_node(val, y, x);
    if(y) son[y][key[y]0);
}
int Find(int val)
{
    int x = root;
    while(x && key[x] != val) x = son[x][key[x]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;
}

你可能感兴趣的:(模板)