POJ 3580 SuperMemo (Splay)

来源:互联网 发布:电力电子技术知乎 编辑:程序博客网 时间:2024/05/24 15:37

思路:

区间的一系列操作, 还有翻转什么的,显然Splay

主要说一下 那个循环右移的操作吧

次数先对总长度取模, 因为相当于有循环节。

然后  这个操作 相当于 把一个区间分成两个子区间, 把后面挪到前面。

假设两个区间是 [s1, e1]和 [s2, e2]

那么先把s2-1 转到根, e2+1 转到根的下面, 将e2转到e2+1的下面,将 e2+1的左子树 切下来。

这样就把后一个区间拿出来了,  同样的操作  将s1-1转到根, s1 转到根的下面, 插到 s1左子树即可。


#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 200000 + 10;int n, m;int num[maxn];const int inf = 0x3f3f3f3f;struct SplayTree{    void Rotate(int x, int f){        int y = pre[x], z = pre[y];        pushdown(x);        pushdown(y);        ch[y][!f] = ch[x][f]; pre[ch[x][f] ] = y;        ch[x][f] = y; pre[y] = x;        pre[x] = z;        if (pre[x]) ch[z][ch[z][1] == y ] = x;        pushup(y);    }    void Splay(int x,int goal){        pushdown(x);        while(pre[x] != goal){            if (pre[pre[x] ] == goal){                Rotate(x, ch[pre[x] ][0] == x);            }            else {                int y = pre[x], z = pre[y];                int f = (ch[z][0] == y);                if (ch[y][f] == x) Rotate(x, !f), Rotate(x, f);                else Rotate(y, f), Rotate(x, f);            }        }        pushup(x);        if (goal == 0) root = x;    }    void RotateTo(int k,int goal){        int x = root;        pushdown(x);        while(sz[ ch[x][0] ] != k){            if (k < sz[ ch[x][0] ]){                x = ch[x][0];            }            else {                k -= (sz[ ch[x][0] ] + 1);                x = ch[x][1];            }            pushdown(x);        }        Splay(x, goal);    }    void clear(){        ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;        top = 0;        root = n = 0;        val[0] = -inf;        Min[0] = inf;        rev[0] = 0;        add[0] = 0;        NewNode(root, -inf);        NewNode(ch[root][1], inf);        pre[n] = root;        sz[root] = 2;    }    void NewNode(int& x,int c){        if (top) x = pool[--top];        else x = ++n;        ch[x][0] = ch[x][1] = pre[x] = 0;        sz[x] = 1;        val[x] = Min[x] = c;    }    void pushup(int x){        sz[x] = 1 + sz[ch[x][0] ] + sz[ch[x][1] ];        Min[x] = min(val[x] , min(Min[ch[x][0] ] , Min[ch[x][1] ]));    }    void pushdown(int x){        if (rev[x]){            update_rev(ch[x][0]);            update_rev(ch[x][1]);            rev[x] = 0;        }        if (add[x]){            update_add(ch[x][0], add[x]);            update_add(ch[x][1], add[x]);            add[x] = 0;        }    }    void init(int pos, int tot){        clear();        cnt = tot;        RotateTo(pos, 0);        RotateTo(pos + 1, root);        build(ch[ ch[root][1] ][0], 1, tot, ch[root][1]);        pushup(ch[root][1]);        pushup(root);    }    void build(int& x,int l,int r,int f){        if (l > r) return ;        int mid = (l + r) >> 1;        NewNode(x, num[mid]);        build(ch[x][0],l, mid-1, x);        build(ch[x][1], mid+1, r, x);        pre[x] = f;        pushup(x);    }    void update_add(int x,int v){        if (!x) return;        val[x] += v;        Min[x] += v;        add[x] += v;    }    void update_rev(int x){        if (!x) return;        swap(ch[x][0], ch[x][1]);        rev[x] ^= 1;    }    void ADD(int l,int r,int c){        RotateTo(l - 1, 0);        RotateTo(r + 1, root);        int key = ch[ch[root][1] ][0];        update_add(key, c);        pushup(ch[root][1]);        pushup(root);    }    int getmin(int l,int r){        RotateTo(l-1,0);        RotateTo(r+1,root);        int key = ch[ch[root][1] ][0];        return Min[key];    }    void reverse(int l, int r){        RotateTo(l-1, 0);        RotateTo(r + 1, root);        int key = ch[ ch[root][1] ][0];        update_rev(key);    }    void erase(int x){        if (!x) return;        pool[top++] = x;        erase(ch[x][0]);        erase(ch[x][1]);    }    void del(int x){        RotateTo(x-1, 0);        RotateTo(x+1, root);        int key = ch[ ch[root][1] ][0];        ch[ ch[root][1] ][0] = 0;        cnt -= sz[key];        erase(key);        pushup(ch[root][1]);        pushup(root);    }    void insert(int pos, int v){        cnt++;        RotateTo(pos, 0);        RotateTo(pos + 1, root);        num[1] = v;        build(ch[ ch[root][1] ][0], 1, 1, ch[root][1]);        pushup(ch[root][1]);        pushup(root);    }    void revolve(int x, int y, int t){        t %= (y-x+1);        if (t < 0) t = y - x + 1 + t;        if (t == 0) return;        int s2 = y - t + 1, e2 = y;        int s1 = x, e1 = s2 - 1;        RotateTo(s2 - 1, 0);        RotateTo(e2 + 1, root);        int haha = ch[root][1];        RotateTo(e2, haha);        int key = ch[ ch[root][1] ][0];        pre[key] = 0;        ch[ch[root][1] ][0] = 0;        pushup(ch[root][1]);        pushup(root);        RotateTo(s1 - 1, 0);        RotateTo(s1, root);        ch[ch[root][1] ][0] = key;        pre[key] = ch[root][1];        pushup(ch[root][1]);        pushup(root);    }    int root, n, cnt, ct, top;    int ch[maxn][2];    int pre[maxn];    int sz[maxn];    int val[maxn];    int Min[maxn];    int add[maxn];    int pool[maxn];    int rev[maxn];}spt;int main(){    int n;    scanf("%d",&n);    for (int i = 1; i <= n; ++i){        scanf("%d", &num[i]);    }    int q;    spt.init(0, n);    scanf("%d", &q);    char op[10];    while(q--){        scanf("%s", op);        if (op[0] == 'A'){            int x, y, d;            scanf("%d %d %d",&x, &y, &d);            spt.ADD(x, y, d);        }        else if (op[0] == 'R'){            if (op[3] == 'E'){                int x, y;                scanf("%d %d",&x, &y);                spt.reverse(x, y);            }            else {                int x, y, t;                scanf("%d %d %d", &x, &y, &t);                spt.revolve(x, y, t);            }        }        else if (op[0] == 'I'){            int x, p;            scanf("%d %d",&x, &p);            spt.insert(x, p);        }        else if (op[0] == 'D'){            int x;            scanf("%d", &x);            spt.del(x);        }        else {            int x, y;            scanf("%d %d", &x, &y);            printf("%d\n", spt.getmin(x, y));        }    }    return 0;}

SuperMemo
Time Limit: 5000MS Memory Limit: 65536KTotal Submissions: 16777 Accepted: 5288Case Time Limit: 2000MS

Description

Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

  1. ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
  2. REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
  3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
  4. INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
  5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
  6. MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2

To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.

Input

The first line contains (≤ 100000).

The following n lines describe the sequence.

Then follows M (≤ 100000), the numbers of operations and queries.

The following M lines describe the operations and queries.

Output

For each "MIN" query, output the correct answer.

Sample Input

51 2 3 4 52ADD 2 4 1MIN 4 5

Sample Output

5

Source

POJ Founder Monthly Contest – 2008.04.13, Yao Jinyu

[Submit]   [Go Back]   [Status]   [Discuss]