题目大意:维护一个数列,6种操作。
add:给某个区间的数都加一个数
insert:在某数后插一个数
delete:删除某一个数
min:查询区间内最小值
reverse:把某一区间的数反转
revolve:某一区间的数循环向后挪d位
题解:
真是标准的splay模板啊。
说起来一年前学的splay现在才能真正写对,好是惭愧……QWQ
add,insert,delete,min都是通过旋转找到指定的区间或位置进行操作,除了min以外其他三个操作完都需update(尤其是add也要,不要忘了!)
reverse需要一个lazy(值为0或1),记录这段区间是否要反转。每次pushdown时只需交换改点左右子,然后把左右子lazy^1就可以了
revolve就先把这一整段区间reverse,然后把这时的前d位与后面的分别reverse
注意:
由于不断会加数,空间应该开够避免re
为了方便起见前后各加一个点,所以操作前要对输入的区间进行相应的处理
求min的时候不要忘了+lazynum!
#include <cstdio> #include <iostream> #define INF 10000000 using namespace std; const int MAXN=100005; struct node { int d,Min,size,lazy,lazynum; node *parent,*ch[2]; }pool[MAXN*4],*root,*rf; int cnt,n; int size(node *p) { if(p) return p->size; return 0; } void update(node *p) { p->size=1+size(p->ch[0])+size(p->ch[1]); p->Min=p->d; if(p->ch[0]) p->Min=min(p->Min,p->ch[0]->Min+p->ch[0]->lazynum); if(p->ch[1]) p->Min=min(p->Min,p->ch[1]->Min+p->ch[1]->lazynum); } void pushdown(node *p) { if(p->lazy) { swap(p->ch[0],p->ch[1]); if(p->ch[0]) p->ch[0]->lazy^=1; if(p->ch[1]) p->ch[1]->lazy^=1; p->lazy=0; } if(p->lazynum) { p->d+=p->lazynum; p->Min+=p->lazynum; if(p->ch[0]) p->ch[0]->lazynum+=p->lazynum; if(p->ch[1]) p->ch[1]->lazynum+=p->lazynum; p->lazynum=0; } } void rotate(node *p,int type)//left:0 right:1 { node *parent=p->parent,*son=p->ch[!type],*gp=p->parent->parent; parent->ch[type]=son; if(son) son->parent=parent; p->ch[!type]=parent; parent->parent=p; p->parent=gp; gp->ch[parent==gp->ch[1]]=p; if(parent==root) root=p; update(parent); update(p); } void splay(node *p,node *target) { while(p->parent!=target) { if(p->parent->parent==target) rotate(p,p==p->parent->ch[1]); else { node *parent=p->parent,*gp=p->parent->parent; int f=parent==gp->ch[0]; if(p==parent->ch[f]) rotate(p,f),rotate(p,!f); else rotate(parent,!f),rotate(p,!f); } } } node *find(node *p,int k) { pushdown(p); if(size(p->ch[0])>=k) return find(p->ch[0],k); else if(size(p->ch[0])==k-1) return p; else return find(p->ch[1],k-1-size(p->ch[0])); } void insert(int x,int d) { node *newnode=&pool[++cnt]; newnode->size=1;newnode->d=newnode->Min=d;newnode->lazy=newnode->lazynum=0; node *p=find(root,x); splay(p,rf); p=find(root,x+1); splay(p,root); p->ch[0]=newnode; newnode->parent=p; update(p);update(p->parent); } void del(int x) { node *p=find(root,x-1); splay(p,rf); p=find(root,x+1); splay(p,root); p->ch[0]=NULL; update(p);update(p->parent); } void add(int x,int y,int d) { if(x>y) swap(x,y); node *p=find(root,x-1); splay(p,rf); p=find(root,y+1); splay(p,root); p->ch[0]->lazynum+=d; update(p);update(p->parent); } int GetMin(int x,int y) { if(x>y) swap(x,y); node *p=find(root,x-1); splay(p,rf); p=find(root,y+1); splay(p,root); return p->ch[0]->Min+p->ch[0]->lazynum; } void reverse(int x,int y) { if(x>y) swap(x,y); node *p=find(root,x-1); splay(p,rf); p=find(root,y+1); splay(p,root); p->ch[0]->lazy^=1; } void revolve(int x,int y,int d) { if(x>y) swap(x,y); d=d%(y-x+1); if(d==0) return; reverse(x,y); reverse(x,x+d-1); reverse(x+d,y); } void inorder(node *p) { pushdown(p); if(p->ch[0]) inorder(p->ch[0]); printf("%d ",p->d); if(p->ch[1]) inorder(p->ch[1]); } int main() { scanf("%d",&n); int m,i,a,x,y; char ch[8]; rf=&pool[++cnt]; root=&pool[++cnt]; root->d=root->Min=INF;root->size=1; root->lazy=root->lazynum=0; root->parent=rf;rf->ch[0]=root; node *p; for(i=1;i<=n;i++) { scanf("%d",&a); p=&pool[++cnt]; p->d=p->Min=a;p->size=1; p->lazy=p->lazynum=0; p->parent=root; root->ch[1]=p; splay(p,rf); } p=&pool[++cnt]; p->d=p->Min=INF;p->size=1; p->lazy=p->lazynum=0; p->parent=root; root->ch[1]=p; splay(p,rf); scanf("%d",&m); while(m --> 0) { cin>>ch; if(ch[0]=='A') { scanf("%d%d%d",&x,&y,&a); x++,y++; add(x,y,a); } else if(ch[0]=='D') { scanf("%d",&x); x++; del(x); } else if(ch[0]=='I') { scanf("%d%d",&x,&y); x++; insert(x,y); } else if(ch[0]=='M') { scanf("%d%d",&x,&y); x++,y++; printf("%d ",GetMin(x,y)); } else if(ch[3]=='E') { scanf("%d%d",&x,&y); x++,y++; reverse(x,y); } else { scanf("%d%d%d",&x,&y,&a); x++,y++; revolve(x,y,a); } } return 0; }