题意:要求维护六种操作:区间加,区间翻转,区间切割(旋转),单点插入删除,区间求最小值
【分析】
整整调了三节课+一个晚上(一点才睡觉啊qwq)…啊尼玛
总的来说这题就是暴力splay
其中有许多子问题,比如区间翻转&区间旋转,参见hdu 3487 play with chain,如果没做过可以先做一下,这样的话更容易调这个程序。
总的来说要修改一个区间[x,y]就是将节点x-1 splay到根,将y+1 splay到根的右子树,然后根的右子树的左子树就是区间[x,y],可以在这上面打一个标记,然后下传。
插入操作与上面的操作相似:把x翻转到根,把x+1翻转到根的右子树,那么根的右子树的左子树为空,新加一个节点即可。
删除与插入类似。
区间加法比较玄妙了…pushdown的时候要将当前节点的左右子树的key(当前权值),add(标记值),mn(维护的最小值)都要加上一个add[now]。
差不多就是这样。谢谢观赏。代码略长176行,仅供参考。
推荐:Monster_Yi写的代码只用了不到2KB,还有谁。
【代码】
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define inf 0x3f3f3f3f
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=210000;
int n,m,sz,opt,root;
int a[mxn],f[mxn],mn[mxn],ch[mxn][2],key[mxn],size[mxn],add[mxn],reverse[mxn];
inline void clear(int x)
{
f[x]=mn[x]=ch[x][0]=ch[x][1]=key[x]=size[x]=add[x]=reverse[x]=0;
}
inline int get(int x)
{
if(ch[f[x]][1]==x) return 1;return 0;
}
inline void pushdown(int now)
{
if(!now) return;
int lson=ch[now][0],rson=ch[now][1];
if(reverse[now])
{
if(lson) reverse[lson]^=1;
if(rson) reverse[rson]^=1;
swap(ch[now][0],ch[now][1]);
reverse[now]=0;
}
if(add[now])
{
if(lson) add[lson]+=add[now],key[lson]+=add[now],mn[lson]+=add[now];
if(rson) add[rson]+=add[now],key[rson]+=add[now],mn[rson]+=add[now];
add[now]=0;
}
}
inline void update(int x)
{
if(!x) return;
size[x]=1;
if(ch[x][0]) size[x]+=size[ch[x][0]];
if(ch[x][1]) size[x]+=size[ch[x][1]];
mn[x]=key[x];
if(ch[x][0]) mn[x]=min(mn[x],mn[ch[x][0]]);
if(ch[x][1]) mn[x]=min(mn[x],mn[ch[x][1]]);
}
inline void newnode(int now,int d,int fa)
{
key[now]=d,f[now]=fa,mn[now]=d,add[now]=reverse[now]=ch[now][0]=ch[now][1]=0,size[now]=1;
}
inline void rotate(int x)
{
pushdown(x);
int fa=f[x],fafa=f[fa],which=get(x);
ch[fa][which]=ch[x][which^1],f[ch[fa][which]]=fa;
ch[x][which^1]=fa,f[fa]=x;
f[x]=fafa;
if(fafa) ch[fafa][ch[fafa][1]==fa]=x;
update(fa),update(x);
}
inline void splay(int x,int lastfa)
{
for(int fa;(fa=f[x])!=lastfa;rotate(x))
if(f[fa]!=lastfa) rotate(get(x)==get(fa)?fa:x);
if(!lastfa) root=x;
}
inline int build(int fa,int l,int r)
{
if(l>r) return 0;
int now=++sz,mid=l+r>>1;
key[now]=a[mid],f[now]=fa,mn[now]=key[now],size[now]=1;
ch[now][0]=build(now,l,mid-1);
ch[now][1]=build(now,mid+1,r);
update(now);
return now;
}
inline int number(int x)
{
int now=root;
while(1)
{
pushdown(now);
if(ch[now][0] && x<=size[ch[now][0]]) now=ch[now][0];
else
{
if(x==size[ch[now][0]]+1) return now;
x=x-size[ch[now][0]]-1;
now=ch[now][1];pushdown(now);
}
}
}
int main()
{
int i,j,x,y,d,t,z;
char c[105];
scanf("%d",&n);
fo(i,2,n+1) scanf("%d",&a[i]);
a[1]=inf,a[n+2]=inf;
root=build(0,1,n+2);
scanf("%d",&m);
while(m--)
{
scanf("%s",c);
if(c[0]=='A') //区间+
{
scanf("%d%d%d",&x,&y,&d);
x++,y++;
x=number(x-1),y=number(y+1);
splay(x,0),splay(y,x);
add[ch[ch[root][1]][0]]+=d;
key[ch[ch[root][1]][0]]+=d;
mn[ch[ch[root][1]][0]]+=d;
}
if(c[0]=='R' && c[3]=='E') //区间翻转
{
scanf("%d%d",&x,&y);
if(x==y) continue;
x++,y++;
x=number(x-1),y=number(y+1);
splay(x,0);
splay(y,x);
reverse[ch[ch[root][1]][0]]^=1;
}
if(c[0]=='R' && c[3]=='O') //区间旋转(拿出来,插进去)
{
scanf("%d%d%d",&z,&y,&t);
if(z==y) continue;
t=((t%(y-z+1))+y-z+1)%(y-z+1);
if(!t) continue;
y++,x=y-t+1;
x=number(x-1),y=number(y+1);
splay(x,0),splay(y,x);
int tmp=ch[ch[root][1]][0];
ch[ch[root][1]][0]=0;
int z1=number(z);
int z2=number(z+1);
splay(z1,0),splay(z2,z1);
ch[ch[root][1]][0]=tmp,f[tmp]=ch[root][1];
}
if(c[0]=='I')
{
scanf("%d%d",&x,&d);
x++;
int x1=number(x);
int x2=number(x+1);
splay(x1,0),splay(x2,x1);
newnode(++sz,d,ch[root][1]);
ch[ch[root][1]][0]=sz;
}
if(c[0]=='D')
{
scanf("%d%d",&x,&d);
x++;
int x1=number(x-1);
int x2=number(x+1);
splay(x1,0);
splay(x2,x1);
// clear(ch[ch[root][1]][0]);
ch[ch[root][1]][0]=0;
}
if(c[0]=='M')
{
scanf("%d%d",&x,&y);
x++,y++;
x=number(x-1);
y=number(y+1);
splay(x,0),splay(y,x);
pushdown(ch[ch[root][1]][0]);
update(ch[ch[root][1]][0]);
printf("%d\n",mn[ch[ch[root][1]][0]]);
}
}
return 0;
}
/*
4
1 2 3 4
10
ADD
*/