【洛谷 P3391】【模板】文艺平衡树 --- 区间翻转(splay)

传送门

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

分析

  1. 按数列的顺序建立一颗Splay
    对此,既可以直接一个个地插入,又可以用类似线段树的方法,直接递归构建一颗比较平衡的Splay
  2. 对于区间的翻转操作,可以参考线段树的lazy-tag。
    若要翻转区间[l,r](不只是翻转,区间操作都差不多)
    • 首先找到第l-1的点与r+1的点。
    • 将l-1移至root,r+1移至root(l-1)的右儿子
    • 此时,root的右儿子的左儿子即为区间[l,r]
    • 将区间翻转(swap左右子树),并加标记
      PS:为了方便处理,最好在数列的首尾分别加入一个节点(下文代码为0, n + 1)

代码

#include <cstdio>
#include <cstdlib>
#include <algorithm>

#define IL inline
#define maxn 100005

using namespace std;

IL int read()
{
    int k = 1;
    int sum = 0;
    char c = getchar();

    for(; '0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;

    for(; '0' <= c && c <= '9'; c = getchar())
        sum =sum * 10 + c - '0';

    return sum*k;
}

struct node
{
    node *father;
    node *son[2];
    int val;
    int size;
    bool lazy;

    IL node(int v = 0, node *f = 0)
    {
        father = f;
        son[0] = son[1] = 0;
        val = v;
        lazy = 0;
        size = 1;       
    }
};
node *root;

int n, m;

IL void clean(node *p)
{
    if(!p->lazy) return ;
    swap(p->son[0], p->son[1]);
    if(p->son[0]) p->son[0]->lazy ^= 1;
    if(p->son[1]) p->son[1]->lazy ^= 1;
    p->lazy ^= 1;
}

IL bool son(node *f, node *p)
{
    return f ? (f->son[1] == p) : -1;
}

IL int size(node *p)
{
    return p ? p->size : 0;
}

IL void updata(node *p)
{
    p->size = size(p->son[0]) + size(p->son[1]) + 1;
}

IL void connect(node *f, node *p,int k)
{
    if(!f) root = p; else f->son[k] = p;
    if(p) p->father = f;
}


IL void rotate(node *p)
{
    node *f = p->father, *g = f->father;
    int x = son(f, p), y = !x;

    connect(f, p->son[y], x);
    connect(g, p, son(g, f));
    connect(p, f, y);

    updata(f);
}

IL void splay(node *p, node *q)
{
    for(node *f, *g; p->father != q;)
    {
        f = p->father;
        g = f->father;

        if(g == q) rotate(p); else
        {
            if(son(g, f) ^ son(f, p))
                rotate(p), rotate(p);
            else
                rotate(f), rotate(p);
        }
    }
    updata(p);
}

IL node *refind(int t)
{
    for(node *p = root; p;)
    {
        clean(p);
        if(t == size(p->son[0]) + 1)
            return p;
        if(t <= size(p->son[0]))
            p = p->son[0];
        else
        {
            t -= size(p->son[0]) + 1;
            p = p->son[1];
        }
    }
}

IL void rever(int x, int y)
{
    node *p1 = refind(x), *p2 = refind(y);
    splay(p1, 0); splay(p2, p1);
    p2->son[0]->lazy ^= 1;
}

IL void build(int l, int r, node *f,int k)
{
    int mid = (l + r) >> 1;
    node *p = new node(mid, f);
    if(!f) root = p; else { f->son[k] = p; }
    if(l <= mid - 1) build(l, mid - 1, p, 0); 
    //if(f) printf("%d %d %d\n", f->val, k, mid);
    if(mid + 1 <= r) build(mid + 1, r, p, 1);
    updata(p);
}

IL void write(node *p)
{
    clean(p);
    if(p->son[0]) write(p->son[0]);
    if((p->val != 0) && (p->val != n+1)) printf("%d ",p->val);
    if(p->son[1]) write(p->son[1]);
}

int main()
{
    n = read();
    m = read();
    build(0, n + 1, 0, 0);
    for(int i = 1, x, y; i <= m ; ++ i)
    {
        x = read() + 1;
        y = read() + 1;
        rever(x - 1, y + 1);
    }
    write(root);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/79395969
今日推荐