Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6668 | Accepted: 2226 | |
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:
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 n (n ≤ 100000).
The following n lines describe the sequence.
Then follows M (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
先是码了一上午,然后调了一下午+一晚上,总算是过掉了。内牛满面啊。。。
splay也算入门了吧。splay果然强大,各种神操作都不在话下。
题目大意:给一个序列,6种操作:
1、ADD a b c:将区间[a,b]都加c;
2、RESERVE a b:将区间[a,b]翻转;
3、REVOLVE a b c:将区间[a,b]循环右移c位;(题目描述可能不是很清楚,不过yy一下也是可以的,注意c可能为负数,即可能要求左移)
4、DEL a:删除第a个位置的数;
5、INSERT a b:在第a个数后面加上数b;
6、MIN a b:询问区间[a,b]的最小值;
好丰富的操作啊啊啊
题目分析:所有操作逐一分析:
1、很常规的操作,lazy标记即可
2、很常规的操作,lazy标记即可
3、循环右移操作,先将右移长度对区间长度取模,得到实际的右移长度c,将区间分成2部分:[a,a+c - 1],[a + c,b],右移的实际效果其实就是将前面2个区间交换,这实际就是应该简单的剪切,粘贴操作,将前面一个区间先剪切下来,在粘贴到后一个区间的后面即可。
其实还有一个更简单的做法,REVOLVE[a,b] = REVERSE[a,b] + REVERSE[a,a + c - 1] + REVERSE[a + c,b],很神奇。。。
4、删除操作,也不难,就是将要删除的节点splay到树根,再将要删除的节点的下一个节点splay到根的右子树,删除树根,合并左右子树即可。
5、插入操作,将a节点splay到树根,a+1节点splay到根的右子树,再把新建的节点插到右子树的左子树上。
6、查询操作,不解释。
详情请见代码:
#include <iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100005; const int INF = 0x7fffffff; int m,n; int next[N + N]; struct node { int l,r,f,mn,add,lazy,key,size; }tree[N + N]; int Min(int a,int b) { return a > b?b:a; } void show(int rt) { if(rt) { show(tree[rt].l); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d key = %2d size = %2d ,mn = %2d\n",rt,tree[rt].l,tree[rt].r,tree[rt].f,tree[rt].key,tree[rt].size,tree[rt].mn); show(tree[rt].r); } } void debug(int rt) { printf("root: %d\n",rt); show(rt); } void init() { tree[0].size = tree[0].lazy = tree[0].add = 0; tree[0].key = tree[0].mn = INF; for(int i = 0;i < N + N;i ++) next[i] = i + 1; } int newnode() { int p = next[0]; next[0] = next[p]; tree[p].lazy = tree[p].add = 0; tree[p].l = tree[p].r = tree[p].f = tree[p].mn = 0; tree[p].size = 1; return p; } void delnode(int p) { next[p] = next[0]; next[0] = p; } void pushup(int rt) { if(rt) { tree[rt].size = tree[tree[rt].l].size + tree[tree[rt].r].size + 1; tree[rt].mn = Min(tree[rt].key,Min(tree[tree[rt].l].mn,tree[tree[rt].r].mn)); } } void pushdown(int rt) { if(!rt) return; int ls = tree[rt].l; int rs = tree[rt].r; if(tree[rt].add) { if(ls) { tree[ls].add += tree[rt].add; tree[ls].key += tree[rt].add; tree[ls].mn += tree[rt].add; } if(rs) { tree[rs].add += tree[rt].add; tree[rs].mn += tree[rt].add; tree[rs].key += tree[rt].add; } tree[rt].add = 0; } if(tree[rt].lazy) { swap(tree[rt].l,tree[rt].r); if(ls) tree[ls].lazy ^= 1; if(rs) tree[rs].lazy ^= 1; tree[rt].lazy = 0; } } void zig(int x) { int p = tree[x].f; pushdown(p); pushdown(x); tree[p].l = tree[x].r; if(tree[x].r) tree[tree[x].r].f = p; pushup(p); tree[x].r = p; tree[x].f = tree[p].f; pushup(x); tree[p].f = x; if(tree[x].f == 0) return; if(tree[tree[x].f].l == tree[x].r) tree[tree[x].f].l = x; else tree[tree[x].f].r = x; } void zag(int x) { int p = tree[x].f; pushdown(p); pushdown(x); tree[p].r = tree[x].l; if(tree[x].l) tree[tree[x].l].f = p; pushup(p); tree[x].l = p; tree[x].f = tree[p].f; pushup(x); tree[p].f = x; if(tree[p].f == 0) return; if(tree[tree[x].f].l == tree[x].l) tree[tree[x].f].l = x; else tree[tree[x].f].r = x; } int splay(int x,int goal) { pushdown(x); int p;//parent while(tree[x].f != goal) { p = tree[x].f; int g = tree[p].f;//grandparent if(g == goal) { if(tree[p].l == x) zig(x); if(tree[p].r == x) zag(x); } else { if(tree[g].l == p && tree[p].l == x)//ll { zig(p); zig(x); } else if(tree[g].l == p && tree[p].r == x)//lr { zag(x); zig(x); } else if(tree[g].r == p && tree[p].r == x)//rr { zag(p); zag(x); } else if(tree[g].r == p && tree[p].l == x)//rl { zig(x); zag(x); } } } pushup(x); return x; } int build(int l,int r,int fa) { if(l > r) return 0; int mid = (l + r)>>1; int p = newnode(); tree[p].l = build(l,mid - 1,p); scanf("%d",&tree[p].key); tree[p].mn = tree[p].key; tree[p].f = fa; tree[p].r = build(mid + 1,r,p); pushup(p); return p; } void prepare(int &root) { root = newnode();//涉及到区间操作,所以左右各加1个点 tree[root].mn = INF; tree[root].key = INF; tree[root].r = newnode(); tree[tree[root].r].mn = INF; tree[tree[root].r].key = INF; tree[tree[root].r].f = root; tree[tree[root].r].l = build(1,n,tree[root].r); pushup(tree[root].r); pushup(root); } int find(int pos,int rt) { if(!rt) return 0; pushdown(rt); if(tree[tree[rt].l].size == pos - 1) return rt; if(tree[tree[rt].l].size >= pos) return find(pos,tree[rt].l); else return find(pos - tree[tree[rt].l].size - 1,tree[rt].r); } int getMax(int rt) { pushdown(rt); while(tree[rt].r) { rt = tree[rt].r; pushdown(rt); } return rt; } int getMin(int rt) { pushdown(rt); while(tree[rt].l) { rt = tree[rt].l; pushdown(rt); } return rt; } void Rotate_interval(int a,int b,int &root) { int l = find(a,root); int r = find(b + 2,root); root = splay(l,0); tree[root].r = splay(r,root); pushup(tree[root].r); pushup(root); } void Add(int a,int b,int c,int &root) { Rotate_interval(a,b,root); tree[tree[tree[root].r].l].add += c; tree[tree[tree[root].r].l].mn += c; tree[tree[tree[root].r].l].key += c; } void Reverse(int a,int b,int &root) { Rotate_interval(a,b,root); tree[tree[tree[root].r].l].lazy ^= 1; } void Revolve(int a,int b,int c,int &root)//右移操作 { Rotate_interval(a,b,root); int len = b - a + 1; c = (c % len + len) % len; if(c == 0) return; c = len - c; // Reverse(a,a + c - 1,root);右移操作其实等价于这3个翻转操作 // Reverse(a + c,b,root);如果看得出来就很简单了 // Reverse(a,b,root);如果看不出来就用下面的笨方法: int p = find(c + 1,tree[tree[root].r].l);//tree[tree[root].r].l是操作区间的root tree[tree[root].r].l = splay(p,tree[root].r);//将操作区间中的第c+1个数splay到区间的root int tmp = tree[tree[tree[root].r].l].l;//那么这个区间的root的左子树就是要移动的区间 tree[tree[tree[root].r].l].l = 0;//那么就是应该剪切粘贴的过程,代码看不清楚,在纸上画画就ok int nt = getMax(tree[tree[root].r].l); tree[tree[root].r].l = splay(nt,tree[root].r); tree[tree[tree[root].r].l].r = tmp; tree[tmp].f = tree[tree[root].r].l; pushup(tree[tree[root].r].l); pushup(tree[root].r); pushup(root); } void Insert(int a,int b,int &root) { int p = newnode(); tree[p].mn = b; tree[p].key = b; int x = find(a + 1,root); root = splay(x,0); x = find(a + 2,root); tree[root].r = splay(x,root); tree[p].f = tree[root].r; tree[tree[root].r].l = p; root = splay(p,0); pushup(root); } void Del(int a,int &root) { int x = find(a + 1,root); root = splay(x,0); x = find(a + 2,root); tree[root].r = splay(x,root); tree[tree[root].l].f = tree[root].r; tree[tree[root].r].l = tree[root].l; x = root; root = tree[x].r; delnode(x); tree[root].f = 0; pushup(root); } void Min_query(int a,int b,int &root) { Rotate_interval(a,b,root); printf("%d\n",tree[tree[tree[root].r].l].mn); } int main() { int root; int a,b,c; char op[20]; while(scanf("%d",&n) != EOF) { init(); prepare(root); scanf("%d",&m); while(m --) { scanf("%s",op); scanf("%d",&a); switch(*op) { case 'A': scanf("%d%d",&b,&c); Add(a,b,c,root);break; case 'R': if(op[3] == 'E') { scanf("%d",&b); Reverse(a,b,root); } else { scanf("%d%d",&b,&c); Revolve(a,b,c,root); } break; case 'I': scanf("%d",&b); Insert(a,b,root); break; case 'D':Del(a,root);break; case 'M': scanf("%d",&b); Min_query(a,b,root); } } } return 0; } //4612K 750MS /* 5 1 2 3 4 5 2 ADD 2 4 1 MIN 4 5 5 1 2 3 4 5 14 MIN 1 1 MIN 2 2 MIN 3 3 MIN 4 4 MIN 5 5 REVOLVE 2 5 2 REVERSE 2 3 REVERSE 4 5 REVERSE 2 5 MIN 1 1 MIN 2 2 MIN 3 3 MIN 4 4 MIN 5 5 8 1 2 3 4 5 6 7 8 30 MIN 2 7 ADD 5 6 -7 MIN 2 7 REVERSE 3 8 MIN 6 8 REVOLVE 1 6 -9 MIN 1 3 DEL 3 MIN 2 4 INSERT 7 5 MIN 5 8 REVOLVE 2 8 11 MIN 6 8 MIN 1 2 ADD 1 2 -5 MIN 1 2 */