Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 9921 | Accepted: 3201 | |
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:
- 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}
- 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}
- REVOLVE x y T: rotate sub-sequence {Ax ... Ay} T times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
- 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}
- DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
- 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 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
—————————————————————分割线——————————————
题目大意:
对一个序列进行7种操作:
区间操作:
(1):ADD x y D 对一段区间都增加一个值value
(2):REVERSE x y 翻转一个区间
(3):REVOLVE x y T 对一个区间向右移动T步(转化成交换两个相邻的区间)
(4):INSERT x P 插入一段区间
(5):DELETE x 删除一段区间
(6):MIN x y 返回一段区间的最小值
思路:
对于右移操作就是讲一段区间分割成两半,然后再合并
[x,a][a+1,y],先将a-1旋转到根,再将a+1旋转到根的右儿子,然后把右儿子的左子树割下来,再将y旋转到根,y+1旋转到根的右儿子,最后将被割下来的子树链接到y+1
注意点:
maxn定义成100001会TL!!!
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define Key_value ch[ch[root][1]][0]
#define REP(i,n) for(int i=0;i<(n);++i)
const int INF=1<<30;
const int maxn=100010;
using namespace std;
int root,tot1,ch[maxn][2],key[maxn],Min[maxn],pre[maxn];
int s[maxn],tot2;
int rev[maxn],add[maxn],size[maxn];
int a[maxn];
int n,q;
void update_rev(int rt){
if(!rt) return ;
swap(ch[rt][0],ch[rt][1]);
rev[rt]^=1;
}
void update_add(int rt,int d){
if(!rt) return ;
key[rt]+=d;
add[rt]+=d;
Min[rt]+=d;
}
void push_up(int rt)
{
int lson=ch[rt][0],rson=ch[rt][1];
size[rt]=size[lson]+size[rson]+1;
Min[rt]=min(key[rt],min(Min[lson],Min[rson]));
}
void push_down(int rt)
{
int lson=ch[rt][0],rson=ch[rt][1];
if(add[rt]) {
update_add(lson,add[rt]);
update_add(rson,add[rt]);
add[rt]=0;
}
if(rev[rt]) {
update_rev(lson);
update_rev(rson);
rev[rt]=0;
}
}
void NewNode(int &rt,int f,int k){
if(tot2) rt=s[tot2--];
else rt=++tot1;
ch[rt][0]=ch[rt][1]=0;
pre[rt]=f;
key[rt]=k;
size[rt]=1;
add[rt]=rev[rt]=0;
Min[rt]=k;
}
void build(int &rt,int l,int r,int f)
{
if(l>r) return ;
int mid=(l+r)>>1;
NewNode(rt,f,a[mid]);
build(ch[rt][0],l,mid-1,rt);
build(ch[rt][1],mid+1,r,rt);
push_up(rt);
}
void Init()
{
root=tot1=tot2=0;
rev[root]=add[root]=ch[root][0]=ch[root][1]=pre[root]=size[root]=0;
Min[root]=INF;
NewNode(root,0,-1);
NewNode(ch[root][1],root,-1);
REP(i,n) scanf("%d",&a[i]);
build(Key_value,0,n-1,ch[root][1]);
push_up(ch[root][1]);
push_up(root);
}
void Rotate(int x,int kind)
{
int y=pre[x];
push_down(y);
push_down(x);
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];
pre[y]=x;
ch[x][kind]=y;
push_up(y);
}
void Splay(int x,int goal)
{
push_down(x);
while(pre[x]!=goal) {
if(pre[pre[x]]==goal) {
Rotate(x,ch[pre[x]][0]==x);
} else {
int y=pre[x];
int kind=ch[pre[y]][0]==y;
if(ch[y][kind]==x) {
Rotate(x,!kind);
Rotate(x,kind);
} else {
Rotate(y,kind);
Rotate(x,kind);
}
}
}
push_up(x);
if(goal==0) root=x;
}
int Get_kth(int rt,int k)
{
push_down(rt);
int z=size[ch[rt][0]]+1;
if(z==k) return rt;
if(z>k) return Get_kth(ch[rt][0],k);
else return Get_kth(ch[rt][1],k-z);
}
void Add(int x,int y,int d)
{
Splay(Get_kth(root,x),0);
Splay(Get_kth(root,y+2),root);
update_add(Key_value,d);
push_up(ch[root][1]);
push_up(root);
}
void Reverse(int x,int y)
{
Splay(Get_kth(root,x),0);
Splay(Get_kth(root,y+2),root);
update_rev(Key_value);
}
void Revolve(int x,int y,int k)
{
if(!k) return ;
int l=y-x+1;
l=y-(k%l+l)%l;
Splay(Get_kth(root,x),0);
Splay(Get_kth(root,l+2),root);
int tmp=Key_value;
Key_value=0;
// pre[Key_value]=0;
push_up(ch[root][1]);
push_up(root);
Splay(Get_kth(root,y-l+x),0);
Splay(Get_kth(root,y-l+x+1),root);
Key_value=tmp;
pre[Key_value]=ch[root][1];
push_up(ch[root][1]);
push_up(root);
}
void Insert(int x,int v)
{
Splay(Get_kth(root,x+1),0);
Splay(Get_kth(root,x+2),root);
NewNode(Key_value,ch[root][1],v);
push_up(ch[root][1]);
push_up(root);
}
void erase(int rt)
{
if(!rt) return ;
s[++tot2]=rt;
erase(ch[rt][0]);
erase(ch[rt][1]);
}
void Delete(int x)
{
Splay(Get_kth(root,x),0);
Splay(Get_kth(root,x+2),root);
erase(Key_value);
pre[Key_value]=0;
Key_value=0;
push_up(ch[root][1]);
push_up(root);
}
int Get_answer(int x,int y)
{
Splay(Get_kth(root,x),0);
Splay(Get_kth(root,y+2),root);
return Min[Key_value];
}
int main(){
while(scanf("%d",&n)!=EOF){
Init();
scanf("%d",&q);
char str[10];
int l,r,k;
while(q--){
scanf("%s",str);
if(!strcmp(str,"ADD")){
scanf("%d%d%d",&l,&r,&k);
Add(l,r,k);
}
else if(!strcmp(str,"REVERSE")){
scanf("%d%d",&l,&r);
Reverse(l,r);
}
else if(!strcmp(str,"REVOLVE")){
scanf("%d%d%d",&l,&r,&k);
Revolve(l,r,k);
}
else if(!strcmp(str,"INSERT")){
scanf("%d%d",&l,&k);
Insert(l,k);
}
else if(!strcmp(str,"DELETE")){
scanf("%d",&l);
Delete(l);
}
else{
scanf("%d%d",&l,&r);
printf("%d\n",Get_answer(l,r));
}
}
}
return 0;
}