SuperMemo
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 16499 Accepted: 5203
Case 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, {A1, A2, ... 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

5
1 
2 
3 
4 
5
2
ADD 2 4 1
MIN 4 5

Sample Output

5

Source

POJ Founder Monthly Contest – 2008.04.13, Yao Jinyu

题意:

add x,y D:第x个数到第y个数之间的数每个加D;

reverse x y:第x个数到第y个数之间全部数翻转;

revolve x y T:第x个数到第y个数之间的数,向后循环流动T次,即后面T个数变成这段子序列的最前面T个,前面的被挤到后面。

insert x P:在第x个数后面插入一个数P。

delete x:删除第x个数。

min x,y:求第x个数到第y个数之间的最小数字。


代码:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL INF = 1e18;
const int maxn = 200005;
int a[maxn];
int ch[maxn][2], fa[maxn];
int sz[maxn], rev[maxn];
LL val[maxn], sum[maxn], add[maxn], Min[maxn];
int tol, rt;

void newNode(int p, int __val, int __fa){
    val[p] = __val;
    sum[p] = __val;
    Min[p] = __val;
    fa[p] = __fa;
    sz[p] = 1;
    rev[p] = add[p] = 0;
    ch[p][0] = ch[p][1] = 0;
}

void mark_add(int p, LL __add){
    add[p] += __add;
    val[p] += __add;
    sum[p] += __add * sz[p];
    Min[p] += __add;
}

void mark_rev(int p){
    rev[p] ^= 1;
    swap(ch[p][0], ch[p][1]);
}

void push_down(int p){
    if(rev[p]){
        mark_rev(ch[p][0]);
        mark_rev(ch[p][1]);
        rev[p] = 0;
    }
    if(add[p]){
        mark_add(ch[p][0], add[p]);
        mark_add(ch[p][1], add[p]);
        add[p] = 0;
    }
}

void push_up(int p){
    int ls = ch[p][0], rs = ch[p][1];
    sz[p] = sz[ls] + sz[rs] + 1;
    sum[p] = sum[ls] + sum[rs] + val[p];
    Min[p] = min(val[p], min(Min[ls], Min[rs]));
}

void Rotate(int x, int t){
    int p = fa[x];
    push_down(p);
    push_down(x);
    fa[x] = fa[p];
    if(fa[p])
        ch[fa[p]][ch[fa[p]][1] == p] = x;
    ch[p][!t] = ch[x][t];
    if(ch[x][t])
        fa[ch[x][t]] = p;
    ch[x][t] = p;
    fa[p] = x;
    push_up(p);
}

void splay(int x, int y){
    if(!x) return;
    push_down(x);
    while(fa[x] != y){
        int p = fa[x];
        if(fa[p] == y){
            push_down(p);
            push_down(x);
            Rotate(x, ch[p][0] == x);
        }else{

           int g = fa[p];
           push_down(g);
           push_down(p);
           push_down(x);
           if(ch[g][0] == p){
                if(ch[p][0] == x){
                    Rotate(p, 1);
                    Rotate(x, 1);
                }else{
                    Rotate(x, 0);
                    Rotate(x, 1);
                }
           }else{
                if(ch[p][1] == x){
                    Rotate(p, 0);
                    Rotate(x, 0);
                }else{
                    Rotate(x, 1);
                    Rotate(x, 0);
                }
           }
        }
    }
    push_up(x);
    if(!y) rt = x;
}

int build(int l, int r, int fa){
    if(l > r) return 0;
    int mid = (l + r) >> 1;
    newNode(mid, a[mid], fa);
    ch[mid][0] = build(l, mid - 1, mid);
    ch[mid][1] = build(mid + 1, r, mid);
    push_up(mid);
    return mid;
}

int get_pos(int k){
    int p = rt;
    while(1){
        push_down(p);
        if(sz[ch[p][0]] >= k)
            p = ch[p][0];
        else if(sz[ch[p][0]] + 1 == k)
            break;
        else{
            k -= sz[ch[p][0]] + 1;
            p = ch[p][1];
        }
    }
    return p;
}

void Add(int a, int b, int c){
    int pre = get_pos(a - 1);
    int nxt = get_pos(b + 1);
    splay(pre, 0);
    splay(nxt, pre);
    mark_add(ch[nxt][0], c);
    push_up(nxt);
    push_up(pre);
}

void Rev(int a, int b){
    int pre = get_pos(a - 1);
    int nxt = get_pos(b + 1);
    splay(pre, 0);
    splay(nxt, pre);
    mark_rev(ch[nxt][0]);
    push_up(nxt);
    push_up(pre);
}

void Ins(int x, int P){
    int nxt = get_pos(x + 1);
    int now = get_pos(x);
    splay(nxt, 0);
    splay(now, nxt);
    ch[now][1] = ++tol;
    newNode(ch[now][1], P, now);
    push_up(now);
    push_up(nxt);
}

void Del(int x){
    int pre = get_pos(x - 1);
    int nxt = get_pos(x + 1);
    splay(pre, 0);
    splay(nxt, pre);
    ch[nxt][0] = 0;
    push_up(nxt);
    push_up(pre);
}

void Revolve(int a, int b, int T){ //[a, c - 1], [c, b]
    int l = b - a + 1;
    int g = (T % l + l) % l + 1;
    if(g == 1) return;//原样不动!
//删除[c, b]
    int c = a + l - g + 1;
    int pre = get_pos(c - 1);
    int nxt = get_pos(b + 1);
    splay(pre, 0);
    splay(nxt, pre);
    int p = ch[nxt][0];
    ch[nxt][0] = 0;
    push_up(nxt);
    push_up(pre);
//将[c, b]插入a的前面
    pre = get_pos(a - 1);
    nxt = get_pos(a);
    splay(pre, 0);
    splay(nxt, pre);
    ch[nxt][0] = p;
    fa[p] = nxt;
    push_up(nxt);
    push_up(pre);
}

int get_min(int a, int b){
    int pre = get_pos(a - 1);
    int nxt = get_pos(b + 1);
    splay(pre, 0);
    splay(nxt, pre);
    return Min[ch[nxt][0]];
}

void init(int n){
    tol = 0;
    ch[0][0] = ch[0][1] = fa[0] = sz[0] = rev[0] = 0;
    val[0] = sum[0] = add[0] = 0;
    Min[0] = INF;
    newNode(rt = n + 1, 0, 0);
    newNode(ch[rt][1] = n + 2, 0, rt);
    ch[ch[rt][1]][0] = build(1, n, ch[rt][1]);
    tol = n + 2;
}

int main(){
    int n, m, x, y, D, P, T;
    char opt[10];
    while(scanf("%d", &n) != EOF){
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        init(n);
        scanf("%d", &m);
        while(m--){
            scanf("%s", opt);
            if(opt[0] == 'A'){
                scanf("%d%d%d", &x, &y, &D); x++; y++;
                Add(x, y, D);
            }else if(opt[0] == 'R' && opt[3] == 'E'){
                scanf("%d%d", &x, &y); x++; y++;
                Rev(x, y);
            }else if(opt[0] == 'R'){
                scanf("%d%d%d", &x, &y, &T); x++; y++;
                Revolve(x, y, T);
            }else if(opt[0] == 'I'){
                scanf("%d%d", &x, &P); x++;
                Ins(x, P);
            }else if(opt[0] == 'D'){
                scanf("%d", &x); x++;
                Del(x);
            }else{
                scanf("%d%d", &x, &y); x++; y++;
                printf("%d\n", get_min(x, y));
            }
        }
    }
    return 0;
}

更多推荐

POJ 3580 SuperMemo(Splay树)