Description
给出一个N个整数构成的序列,有M次操作,每次操作有一下三种:
①Insert Y X,在序列的第Y个数之前插入一个数X;
②Add L R X,对序列中第L个数到第R个数,每个数都加上X;
③Query L R,询问序列中第L个数到第R个数的平方和。
Time Limits:2000ms
Analysis
插入的话,splay好做,平方和什么的区间维护好做
size表示区间点数,sum表示区间和,sum2表示区间平方和,add表示tag,key表示该点键值
这题因为有区间修改所以要打lazy tag
实现细节:
- 开longlong
- 因为头尾各有一个空结点,所以区间修改的时候注意:空结点的sum,size,sum2都要修改,但是key永远为0,修改的时候要特判,不能动。
- 建议将提取区间写成一个函数,一次性写好,要不然用size[a[x][0]]+1的时候如果忘记splay到根就会跪(之前老是忘)
- 开完虚拟结点n+2后,要记得将表示结点数量的变量n赋为n+2
Code
#include<cstdio>
#include<stack>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=200010,mo=7459;
int n,root,size[N],add[N],f[N],a[N][2];
ll key[N],sum[N],sum2[N];
stack<int> q;
int pd(int x)
{
return x==a[f[x]][1];
}
int update(int x)
{
size[x]=1+size[a[x][0]]+size[a[x][1]];
sum[x]=key[x]+sum[a[x][0]]+sum[a[x][1]];
sum2[x]=((key[x]*key[x]%mo+sum2[a[x][0]]+sum2[a[x][1]])%mo+mo)%mo;
}
void change(int x,ll z)
{
if(!x) return;
sum2[x]=((sum2[x]+z*z*size[x]%mo+2*sum[x]*z%mo)%mo+mo)%mo,sum[x]+=size[x]*z,add[x]+=z;
if(x<=n) key[x]+=z;
}
void down(int x)
{
if(!add[x]) return;
change(a[x][0],add[x]);
change(a[x][1],add[x]);
add[x]=0;
}
void remove(int x,int y)
{
for(;x!=y;x=f[x]) q.push(x);
while(!q.empty())
{
down(q.top());q.pop();
}
}
void rotate(int x)
{
int y=f[x],z=pd(x);
a[y][z]=a[x][1-z];
if(a[x][1-z]) f[a[x][1-z]]=y;
f[x]=f[y];
if(f[y]) a[f[y]][pd(y)]=x;
f[y]=x,a[x][1-z]=y;
update(y);
}
void splay(int x,int y)
{
if(!y) root=x;
remove(x,y);
while(f[x]!=y)
{
if(f[f[x]]!=y)
if(pd(x)==pd(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
update(x);
}
int kth(int x,int k)
{
if(size[a[x][0]]+1==k) return x;
if(k>size[a[x][0]]) return kth(a[x][1],k-size[a[x][0]]-1);
else return kth(a[x][0],k);
}
int split(int x,int y)
{
x=kth(root,x),y=kth(root,y+2);
splay(x,0),splay(y,x);
return a[y][0];
}
int main()
{
int _,x,y,z;
char ch;
scanf("%d",&n);
fo(i,1,n) scanf("%lld",&key[i]);
f[1]=n+1,key[n+1]=0,a[n+1][1]=1;
fo(i,2,n) f[i]=i-1,a[i-1][1]=i;
f[n+2]=n,key[n+2]=0,a[n][1]=n+2,size[n+2]=1;
splay(n+2,0);
n=n+2;
for(scanf("%d\n",&_);_;_--)
{
scanf("%c",&ch);
if(ch=='Q')
{
scanf("uery %d %d\n",&x,&y);
x=split(x,y);
printf("%lld\n",sum2[x]);
}
if(ch=='I')
{
scanf("nsert %d %d\n",&y,&z);
x=kth(root,y);
y=kth(root,y+1);
splay(x,0),splay(y,x);
a[y][0]=++n,f[n]=y,key[n]=z;
splay(n,0);
}
if(ch=='A')
{
scanf("dd %d %d %d\n",&x,&y,&z);
x=split(x,y);
change(x,z);
}
}
return 0;
}