POJ3580 SuperMemo (Splay Tree的各种操作)

版权声明:希望有人转(^_^) https://blog.csdn.net/Sunshine_cfbsl/article/details/52234656

这题基本上就是 Splay Tree 维护区间的终极题了。
AC后就能领悟到 Splay Tree 的真谛(O_O)
Splay Tree模板戳这里
题目大意:
对于一个数列 {A1,A2,...,An} ,写一个程序能够实现以下操作:

  • ADD x y D:给数列 {Ax,...,Ay} 中的每一个数都增加 D
  • REVERSE x y: 将数列 {Ax,...,Ay} 翻转过来
  • REVOLVE x y T:将数列 {Ax,...,Ay} 中每一个数向右移动 T 位,其中第 y 位向右移动一位后到 x 的位置
  • INSERT x P:在 Ax 后插入数字 P
  • DELETE x:删除 Ax
  • MIN x y:求数列 {Ax,...,Ay} 的最小值

一眼就可以看出用 Splay Tree 做,然而就是编程难度较大。
之前一直拒绝使用 Splay(x,r) (即将x旋转到r的下方),然而对于区间操作,这样就是比 Splay(x) (即将x旋转到根节点)要好写一些QAQ。
代码如下:

/*
ID: Sunshine_cfbsl
LANG: C++
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int MAXN = 200010, INF = 1000000000;
int n, m;
struct Splay_Tree {
    int fa[MAXN], ch[MAXN][2], v[MAXN], size[MAXN], flag[MAXN], r, pn, Min[MAXN];
    bool rev[MAXN];
    void clear(int x) { 
        r = pn = size[1] = 1;
        Min[0] = INF;
        v[1] = Min[1] = x;
    }
    void update(int p, int e, bool rever) {
        if(p == 0) return;
        flag[p] += e;
        v[p] += e;
        Min[p] += e;
        if(rever) {
            swap(ch[p][0], ch[p][1]);
            rev[p] ^= true;
        }
    }
    void push_down(int p) {
        if(flag[p] || rev[p]) {
            update(ch[p][0], flag[p], rev[p]);
            update(ch[p][1], flag[p], rev[p]);
            flag[p] = rev[p] = 0;
        }
    }
    void maintain(int p) {
        Min[p] = min(min(Min[ch[p][0]], Min[ch[p][1]]), v[p]);
        size[p] = size[ch[p][0]] + size[ch[p][1]] + 1;
    }
    void Rotate(int p, bool t) {
        int f = fa[p];
        push_down(f);
        push_down(p);
        fa[ch[f][t^1] = ch[p][t]] = f;
        fa[ch[fa[f]][ch[fa[f]][1]==f] = p] = fa[f];
        ch[fa[f] = p][t] = f;
        maintain(f);
    }
    void splay(int x, int end) {
        push_down(x);
        while(fa[x] != end) {
            int p = fa[x];
            if(fa[p] == end) {
                Rotate(x, x==ch[p][0]);
                break;
            }
            bool f = x==ch[p][0], f1 = p==ch[fa[p]][0], f2 = p==ch[fa[p]][1];
            Rotate(f?f1?p:x:f2?p:x, f);
            Rotate(x, f1);
        }
        maintain(x);
        if(end == 0) r = x;
    }
    void init(int y) {
        fa[ch[r][1] = ++pn] = r;
        v[pn] = Min[pn] = y;
        size[pn] = 1;
        splay(pn, 0);
    }
    int find(int x) {
        int p = r;
        while(size[p] ^ 1) {
            push_down(p);
            if(size[ch[p][0]]+1 == x) break;
            if(x > size[ch[p][0]]) {
                x -= (size[ch[p][0]]+1);
                p = ch[p][1];
            }
            else p = ch[p][0];
        }
        return p;
    }
    int query(int s, int t) {
        splay(find(s), 0);
        splay(find(t), r);
        return Min[ch[ch[r][1]][0]];
    }
    void add(int s, int t, int e) {
        splay(find(s), 0);
        splay(find(t), r);
        update(ch[ch[r][1]][0], e, 0);
    }
    void del(int p) {
        splay(p = find(p), 0);
        splay(find(size[ch[r][0]]), r);
        r = ch[r][0];
        fa[r] = 0;
        fa[ch[r][1] = ch[p][1]] = r;
        maintain(r);
    }
    void insert(int x, int value) {
        splay(find(x), 0);
        splay(find(x+1), r);
        int u = ch[r][1];
        fa[ch[u][0] = ++pn] = u;
        size[pn] = 1;
        v[pn] = Min[pn] = value;
        maintain(u);
        maintain(r);
    }
    void reverse(int s, int t) {
        splay(find(s), 0);
        splay(find(t), r);
        update(ch[ch[r][1]][0], 0, 1);
    }
    void revolve(int s, int t, int k) {
        k = (k%(t-s+1)+(t-s+1))%(t-s+1);
        splay(find(t-k), 0);
        splay(find(t+1), r);
        int u = ch[ch[r][1]][0];
        fa[u] = ch[ch[r][1]][0] = 0;
        maintain(ch[r][1]);
        maintain(r);
        splay(find(s-1), 0);
        splay(find(s), r);
        ch[fa[u] = ch[r][1]][0] = u;
        maintain(ch[r][1]);
        maintain(r);
    }
}tree;

int main() {
    int i, tmp, x, y, d;
    char str[20];
    scanf("%d", &n);
    tree.clear(INF);
    for(i = 1; i <= n; i++) {
    scanf("%d", &tmp);
    tree.init(tmp);
    }
    tree.init(INF);
    scanf("%d", &m);
    for(i = 1; i <= m; i++) {
        scanf("%s", str);
        if(str[0] == 'A') {
            scanf("%d%d%d", &x, &y, &d);
            if(x > y) swap(x, y);
            tree.add(x, y+2, d);
        }
        if(str[0] == 'R' && str[3] == 'E') {
            scanf("%d%d", &x, &y);
            if(x > y) swap(x, y);
            tree.reverse(x, y+2);
        }
        if(str[0] == 'R' && str[3] == 'O') {
            scanf("%d%d%d", &x, &y, &d);
            if(x > y) swap(x, y);
            tree.revolve(x+1, y+1, d);
        } 
        if(str[0] == 'I') {
            scanf("%d%d", &x, &d);
            tree.insert(x+1, d);
        }
        if(str[0] == 'D') {
            scanf("%d", &x);
            tree.del(x+1);
        }
        if(str[0] == 'M') {
            scanf("%d%d", &x, &y);
            if(x > y) swap(x, y);
            printf("%d\n", tree.query(x, y+2));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Sunshine_cfbsl/article/details/52234656
今日推荐