给你一个长度为N的序列{ai}和M个操作
1.查询第k个数的值
2.将第k个数增加d
3.查询一段区间的和
4.查询一段区间的最大值
5.将一段区间镜面翻转(例如序列{1,2,3,4,5,6},将从2到5的区间翻转后得到序列{1,5,4,3,2,6})
对于除操作2,5以外的操作,输出相应的答案
第一行两个正整数N,M
第二行N个整数,为初始的序列
第三行到底M+2行,每行若干个整数
·如果第一个数为1,那么后面一个正整数k,表示查询第k个数的值
·如果第一个数是2,那么后面两个正整数k,d,表示将ak增加d
·如果第一个数为3,那么后面两个正整数l,r,表示查询从al到ar的区间和
·如果第一个数为4,那么后面两个正整数l,r,表示查询从al到ar的最大值
·如果第一个数为5,那么后面两个正整数l,r,表示翻转从al到ar的这个区间
除操作2,5外每个操作输出占一行,一个整数,为本次提问的答案
6 8
1 2 3 4 5 6
1 4
3 2 5
4 2 2
5 2 5
3 1 3
5 2 5
2 5 1
4 1 6
4
14
2
10
6
2<=N<=100000
1<=M<=100000
原序列1<=ai<=1000
每次1<=k<=N,1<=l<=r<=N,1<=d<=1000
我们维护一棵平衡树,键值为各点的编号。一个点的左子树的实际位置在这个点之前,右子树的实际位置在这个点之后。初始时任一点的左子树(如果有的话)编号全部小于该点编号,右子树编号全部大于该点编号。并记录好每个点为根的树的最大元素、元素和。
一号操作,我们只用类似于平衡树“查询第K小”的方法就可以了。
二号,先将这个点找到(见一号操作),再旋到根。这样,修改操作就只会对根节点有影响了。
三号,找到第(L-1)个数的编号,旋到根。再找到第(R+1)个数,旋到根的右儿子。输出(R+1)个数的左儿子的元素和就行了(解释略)。
四号同三号。
五号,略同三号,在(R+1)个数的左儿子打一个Lazy标记,以后讨论到带标记的点就交换左右儿子并下放标记。由于偶数个标记不影响结果,建议使用异或修改标记。
用的splay
#include
#include
#include
using namespace std;
const int Q=100005;
int si[Q],ls[Q],rs[Q],f[Q],v[Q],maxn[Q],sum[Q],root=1,n,ch[Q]={0};
void lx(int x)
{
int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
rs[y]=ls[x];
f[rs[y]]=y;
f[x]=z;
f[y]=x;
ls[x]=y;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+1;
maxn[x]=maxn[y];
maxn[y]=max(max(maxn[ls[y]],maxn[rs[y]]),v[y]);
sum[x]=sum[y];
sum[y]=sum[ls[y]]+sum[rs[y]]+v[y];
}
void rx(int x)
{
int y=f[x],z=f[y];
if(z)if(ls[z]==y)ls[z]=x;
else rs[z]=x;
ls[y]=rs[x];
f[ls[y]]=y;
f[x]=z;
f[y]=x;
rs[x]=y;
si[x]=si[y];
si[y]=si[ls[y]]+si[rs[y]]+1;
maxn[x]=maxn[y];
maxn[y]=max(max(maxn[ls[y]],maxn[rs[y]]),v[y]);
sum[x]=sum[y];
sum[y]=sum[ls[y]]+sum[rs[y]]+v[y];
}
void pd(int x)
{
swap(ls[x],rs[x]);
if(ls[x])ch[ls[x]]^=1;
if(rs[x])ch[rs[x]]^=1;
ch[x]=0;
}
void splay(int x,int goal)
{
while(f[x]!=goal&&f[x]!=0)
{
if(ch[x])pd(x);
int y=f[x],z=f[y];
if(z!=0&&z!=goal)
{
if(ch[z])pd(z);
if(ch[y])pd(y);
if(ls[z]==y)
if(ls[y]==x)rx(y),rx(x);
else lx(x),rx(x);
else if(rs[y]==x)lx(y),lx(x);
else rx(x),lx(x);
}
else
{
if(ch[y])pd(y);
if(ls[y]==x)rx(x);
else lx(x);
}
}
if(f[x]==0)root=x;
}
int gk(int k)
{
if(k==0)return 0;
si[0]=0;
int p=root;
while(p)
{
if(ch[p])pd(p);
if(si[ls[p]]+1==k)break;
if(si[ls[p]]ls[p]]+1,p=rs[p];
else p=ls[p];
}
return p;
}
int main()
{
int i,x,m,y;
scanf("%d%d",&n,&m);
f[1]=0;
for(i=1;i<=n+1;i++)
{
if(i<=n)scanf("%d",&v[i]);
si[i]=1;
maxn[i]=sum[i]=v[i];
if(i==1)continue;
x=root;
while(x)
{
si[x]++;
sum[x]+=v[i];
maxn[x]=max(maxn[x],v[i]);
if(i>x)if(rs[x])x=rs[x];
else {rs[x]=i;break;}
else if(ls[x])x=ls[x];
else {ls[x]=i;break;}
}
f[i]=x;
splay(i,0);
}
while(m--)
{
scanf("%d",&i);
if(i==1)scanf("%d",&x),printf("%d\n",v[gk(x)]);
if(i==2)
{
scanf("%d%d",&x,&y);
x=gk(x);
splay(x,0);
v[x]+=y;
sum[x]+=y;
maxn[x]=max(maxn[x],v[x]);
}
if(i==3||i==4)
{
scanf("%d%d",&x,&y);
x=gk(x-1),y=gk(y+1);
if(x)splay(x,0);
splay(y,x);
if(i==3)printf("%d\n",sum[ls[y]]);
else printf("%d\n",maxn[ls[y]]);
}
if(i==5)
{
scanf("%d%d",&x,&y);
x=gk(x-1),y=gk(y+1);
if(x)splay(x,0);
splay(y,x);
ch[ls[y]]^=1;
}
}
return 0;
}