题目大意
给出一个N个整数构成的序列,有M次操作,每次操作有一下三种:
①Insert Y X,在序列的第Y个数之前插入一个数X;
②Add L R X,对序列中第L个数到第R个数,每个数都加上X;
③Query L R,询问序列中第L个数到第R个数的平方和。
30%的数据满足N≤1,000,M≤1,000。
另外20%的数据满足N≤100,000,M≤100,000,且不存在Insert操作。
100%的数据满足N≤100,000,M≤100,000,且Add和Insert操作中|X|≤1000,|Ai|≤1000。
序列之王好
我们可以用splay来做这道题。
对于第一个操作,这是splay基本操作。
现在,为了支持第三个操作,我们维护size[i]表示以i为根的子树有多少元素,num[i]表示以i为根的子树元素和,sum[i]表示以i为根的子树元素平方和。
那么,这很容易维护。
为了支持第二个操作,我们用add[i]表示以i为根的子树每个元素都加上add[i]。则对于i而言,sum[i]需改为
sum[i]+add[i]2∗size[i]+2∗add[i]∗num[i]
。
num[i]改为
num[i]+add[i]∗size[i]
。
然后维护标记即可。
参考代码
#include<cstdio>
#include<cstring>
#include<stack>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000*2+5,mo=7459;
stack <int> s;
int size[maxn],key[maxn],num[maxn],sum[maxn],add[maxn],father[maxn],tree[maxn][2];
int i,j,k,l,r,mid,t,n,m,tot,root,x,y;
char ch;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
char get(){
char ch=getchar();
while (ch<'A'||ch>'Z') ch=getchar();
return ch;
}
int pd(int x){
if (x==tree[father[x]][0]) return 0;else return 1;
}
void updata(int x){
size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
sum[x]=((sum[tree[x][0]]+sum[tree[x][1]])%mo+key[x]*key[x]%mo)%mo;
num[x]=((num[tree[x][0]]+num[tree[x][1]])%mo+key[x])%mo;
}
void rotate(int x){
int y=father[x],z=pd(x);
father[x]=father[y];
if (father[y]) tree[father[y]][pd(y)]=x;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) father[tree[x][1-z]]=y;
tree[x][1-z]=y;
father[y]=x;
updata(y);
updata(x);
}
void clear(int x){
if (add[x]){
if (tree[x][0]){
key[tree[x][0]]=(key[tree[x][0]]+add[x])%mo;
sum[tree[x][0]]=((sum[tree[x][0]]+add[x]*add[x]%mo*size[tree[x][0]])%mo+2*add[x]%mo*num[tree[x][0]]%mo)%mo;
num[tree[x][0]]=(num[tree[x][0]]+add[x]*size[tree[x][0]]%mo)%mo;
add[tree[x][0]]=(add[tree[x][0]]+add[x])%mo;
}
if (tree[x][1]){
key[tree[x][1]]=(key[tree[x][1]]+add[x])%mo;
sum[tree[x][1]]=((sum[tree[x][1]]+add[x]*add[x]%mo*size[tree[x][1]])%mo+2*add[x]%mo*num[tree[x][1]]%mo)%mo;
num[tree[x][1]]=(num[tree[x][1]]+add[x]*size[tree[x][1]]%mo)%mo;
add[tree[x][1]]=(add[tree[x][1]]+add[x])%mo;
}
add[x]=0;
}
}
void remove(int x,int y){
while (x!=y){
s.push(x);
x=father[x];
}
while (!s.empty()){
clear(s.top());
s.pop();
}
}
void splay(int x,int y){
remove(x,y);
while (father[x]!=y){
if (father[father[x]]!=y)
if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x);
rotate(x);
}
}
int kth(int x,int y){
if (size[tree[x][0]]+1==y) return x;
else if (size[tree[x][0]]+1>y) return kth(tree[x][0],y);
else return kth(tree[x][1],y-size[tree[x][0]]-1);
}
void split(int x,int y,int &l,int &r){
if (!y){
l=0;
r=x;
}
else{
int z=kth(x,y);
splay(z,0);
r=tree[z][1];
father[r]=0;
l=z;
tree[l][1]=0;
updata(l);
}
}
void merge(int l,int r,int &x){
if (!l) x=r;
else if (!r) x=l;
else{
int z=kth(l,size[l]);
splay(z,0);
father[r]=z;
tree[z][1]=r;
x=z;
updata(x);
}
}
int main(){
n=read();
tot=n;
fo(i,1,n){
key[i]=read();
key[i]=(key[i]%mo+mo)%mo;
if (i>1){
father[i-1]=i;
tree[i][0]=i-1;
}
size[i]=i;
updata(i);
}
root=n;
splay(1,0);
root=1;
m=read();
fo(i,1,m){
ch=get();
if (ch=='I'){
y=read();x=read();
x=(x%mo+mo)%mo;
key[++tot]=x;
updata(tot);
split(root,y-1,l,r);
merge(tot,r,r);
merge(l,r,root);
}
if (ch=='A'){
x=read();y=read();t=read();
t=(t%mo+mo)%mo;
split(root,y,l,r);
split(l,x-1,l,mid);
key[mid]=(key[mid]+t)%mo;
sum[mid]=((sum[mid]+t*t%mo*size[mid])%mo+2*t%mo*num[mid]%mo)%mo;
num[mid]=(num[mid]+t*size[mid]%mo)%mo;
add[mid]=(add[mid]+t)%mo;
merge(l,mid,l);
merge(l,r,root);
}
if (ch=='Q'){
x=read();y=read();
split(root,y,l,r);
split(l,x-1,l,mid);
printf("%d\n",sum[mid]);
merge(l,mid,l);
merge(l,r,root);
}
}
}