SuperMemo

Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 19781 Accepted: 6220
Case Time Limit: 2000MS

Description

Your friend, Jackson is invited to a T V TV 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, { A 1 , A 2 , . . . A n } \{A_1, A_2, ... A_n\} {A1,A2,...An}. Then the host performs a series of operations and queries on the sequence which consists:

A D D   x   y   D ADD\ x\ y\ D ADD x y D: Add D D D to each number in sub-sequence { A x . . . A y } \{A_x ... A_y\} {Ax...Ay}. For example, performing “ A D D   2   4   1 ADD\ 2\ 4\ 1 ADD 2 4 1” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} results in { 1 , 3 , 4 , 5 , 5 } \{1, 3, 4, 5, 5\} {1,3,4,5,5}
R E V E R S E   x   y REVERSE\ x\ y REVERSE x y: reverse the sub-sequence { A x . . . A y } \{A_x ... A_y\} {Ax...Ay}. For example, performing “ R E V E R S E   2   4 REVERSE\ 2\ 4 REVERSE 2 4” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} results in { 1 , 4 , 3 , 2 , 5 } \{1, 4, 3, 2, 5\} {1,4,3,2,5}
R E V O L V E   x   y   T REVOLVE\ x\ y\ T REVOLVE x y T: rotate sub-sequence { A x . . . A y } \{A_x ... A_y\} {Ax...Ay} T times. For example, performing “ R E V O L V E   2   4   2 REVOLVE\ 2\ 4\ 2 REVOLVE 2 4 2” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} results in { 1 , 3 , 4 , 2 , 5 } \{1, 3, 4, 2, 5\} {1,3,4,2,5}
I N S E R T   x   P INSERT\ x\ P INSERT x P: insert P P P after A x A_x Ax. For example, performing “ I N S E R T   2   4 INSERT\ 2\ 4 INSERT 2 4” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} results in { 1 , 2 , 4 , 3 , 4 , 5 } \{1, 2, 4, 3, 4, 5\} {1,2,4,3,4,5}
D E L E T E   x DELETE\ x DELETE x: delete Ax. For example, performing “ D E L E T E   2 DELETE\ 2 DELETE 2” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} results in { 1 , 3 , 4 , 5 } \{1, 3, 4, 5\} {1,3,4,5}
M I N   x   y MIN\ x\ y MIN x y: query the participant what is the minimum number in sub-sequence { A x . . . A y } \{A_x ... A_y\} {Ax...Ay}. For example, the correct answer to “ M I N   2   4 MIN\ 2\ 4 MIN 2 4” on { 1 , 2 , 3 , 4 , 5 } \{1, 2, 3, 4, 5\} {1,2,3,4,5} is 2 2 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 T V TV 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 n ( n ≤ 100000 ) n (n \leq 100000) n(n100000).
The following n n n lines describe the sequence.

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

The following M M M lines describe the operations and queries.

Output

For each “ M I N MIN 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

题解

  • 算是比较全的splay功能模版题了

代码

#include<cstdio>
#include<iostream>

using namespace std;
#define inf 0x3f3f3f3f
const int maxn=2e5+10;

/*
说明:
此splay树不能同时支持查询rank操作,如果需要同时支持区间翻转和查询rank,则需要写树套树,或者以值为中序写splay树
*/

struct splay_tree{
    int tot,root,ch[maxn][2],fa[maxn],siz[maxn];//mark第二维表示存不同的标记
    int minn[maxn],val[maxn],mark[maxn][3];
    splay_tree(){      
        tot=2;root=1;
        ch[1][1]=2;fa[2]=1;fa[1]=0;siz[1]=2;siz[2]=1;val[2]=minn[2]=inf;val[1]=minn[1]=-inf;  //插入两个边界的数方便区间翻转和元素删除操作
    }

    int dir(int x){
        return ch[fa[x]][1]==x;
    }

    void pushup(int x){
        siz[x]=1;minn[x]=val[x];
        if(ch[x][0]) minn[x]=min(minn[x],minn[ch[x][0]]),siz[x]+=siz[ch[x][0]];
        if(ch[x][1]) minn[x]=min(minn[x],minn[ch[x][1]]),siz[x]+=siz[ch[x][1]];
    }

    void down(int x){
        if(mark[x][0]){  //翻转标记
            swap(ch[x][0],ch[x][1]);
            mark[ch[x][0]][0]^=1;
            mark[ch[x][1]][0]^=1;
            mark[x][0]=0;
        }
        if(mark[x][1]){   //区间加
            mark[ch[x][0]][1]+=mark[x][1];
            mark[ch[x][1]][1]+=mark[x][1];
            val[ch[x][0]]+=mark[x][1];minn[ch[x][0]]+=mark[x][1];
            val[ch[x][1]]+=mark[x][1];minn[ch[x][1]]+=mark[x][1];
            mark[x][1]=0;
        }
    }

    void rotate(int x){
        int y=fa[x],z=fa[y],k=dir(x);
        down(y);down(x);
        ch[y][k]=ch[x][k^1];fa[ch[x][k^1]]=y;
        ch[z][dir(y)]=x;fa[x]=z;
        ch[x][k^1]=y;fa[y]=x;
        pushup(y);pushup(x);
    }

    void splay(int x,int goal=0){
        while(fa[x]!=goal){
            int y=fa[x],z=fa[y];
            if(z!=goal) {
                if(dir(x)==dir(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
        if(!goal) root=x;
    }

    int kth(int x){  //返回第x大,返回的是下标
        int cur=root;
        while(true){
            down(cur);
            if(ch[cur][0]&&x<=siz[ch[cur][0]]){
                cur=ch[cur][0];
            }else if(x>siz[ch[cur][0]]+1){
                x-=(siz[ch[cur][0]]+1);
                cur=ch[cur][1];
            }else return cur;  
        }
    }
    
    void insert(int pos,int value){  //x 为插入的位置,value为插入的值
        int cur=kth(pos),rson=kth(pos+1);
        splay(cur),splay(rson,root);
        
        ch[rson][0]=++tot;fa[tot]=rson;
        ch[tot][0]=ch[tot][1]=0;siz[tot]=1;
        val[tot]=minn[tot]=value;
        pushup(rson);pushup(root);
        splay(cur); //splay到根节点,保持树平衡
    }

    void erase(int pos){  //erase的是pos
        int cur=kth(pos),rson=kth(pos+2);
        splay(cur);splay(rson,root);
        ch[ch[rson][0]][0]=ch[ch[rson][0]][1]=0;
        val[ch[rson][0]]=minn[ch[rson][0]]=0;fa[ch[rson][0]]=0;siz[ch[rson][0]]=0;
        ch[rson][0]=0;
        pushup(rson);pushup(root);
    }

    void revolve(int l,int r,int t){ //将区间[l,r]旋转t次,如1 2 3 4 5 旋转2次后就变成4 5 1 2 3
        t=(t%(r-l+1)+(r-l+1))%(r-l+1);
        if(!t) return;
        int cur=kth(r-t+1),rson=kth(r+2);
        splay(cur);splay(rson,root);
        int memor=ch[rson][0];ch[rson][0]=0;
        cur=kth(l);rson=kth(l+1);
        splay(cur);splay(rson,root);
        ch[rson][0]=memor;fa[memor]=rson;
    }

    void modify(int l,int r,int add){ //区间加
        int cur=kth(l),rson=kth(r+2);
        splay(cur);splay(rson,root);
        minn[ch[rson][0]]+=add;
        val[ch[rson][0]]+=add;
        mark[ch[rson][0]][1]+=add;
        pushup(rson);pushup(root);
    }

    int query_min(int l,int r){
        int cur=kth(l),rson=kth(r+2);
        splay(cur);splay(rson,root);
        return minn[ch[rson][0]];
    }

    void reverse(int l,int r){
        int cur=kth(l),rson=kth(r+2);
        splay(cur);splay(rson,root);
        mark[ch[rson][0]][0]^=1;
    }

    void mid_visit(int cur){ //中序遍历
        down(cur);
        if(ch[cur][0]) mid_visit(ch[cur][0]);
        printf("%d ",val[cur]);
        if(ch[cur][1]) mid_visit(ch[cur][1]);
    }
}tree;

int n,m,l,r,t,x,a,add,val;
char opt[50];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a);
        tree.insert(i,a);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%s",opt+1);
        if(opt[1]=='A'){
            scanf("%d %d %d",&l,&r,&add);
            tree.modify(l,r,add);
        }else if(opt[1]=='R'){
            if(opt[4]=='E'){
                scanf("%d %d",&l,&r);
                tree.reverse(l,r);
                //tree.mid_visit(tree.root);
            }else{
                scanf("%d %d %d",&l,&r,&t);
                tree.revolve(l,r,t);
            }
        }else if(opt[1]=='I'){
            scanf("%d %d",&x,&val);
            tree.insert(x+1,val);  //在x后面插要加一
        }else if(opt[1]=='D'){
            scanf("%d",&x);
            tree.erase(x);
        }else{
            scanf("%d %d",&l,&r);
            printf("%d\n",tree.query_min(l,r));
        }
    }
}

更多推荐

「POJ3580」SuperMemo【splay】