K. Krystalova’s Trivial Problem
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
题目描述
Krystalova is writing trivial problems (as always) but now for some reason (lucky for you) she also wrote a trivial statement.
You have a trivial list of numbers L, and two trivial operations:
-
u l r x: Add x to the numbers in L in the range [l,r].
-
q l r: Get the sum of L2i for every i in the range [l,r].
输入描述
In the first line of input two integers N (1≤N≤10^5), Q (1≤Q≤10^4), the size of L and the number of operations respectively.
The next line contains N integers Li (0≤Li≤10^8), the elements of L.
The next Q lines contains an operation, that can be one of the two types described before. If the line starts with a letter “u” then will be three integers l (1≤l≤N), r (1≤r≤N), x (−108≤x≤108). If the line starts with a letter “q” then will be two integers l (1≤l≤N), r (1≤r≤N)
输出描述
For every operation of type 2, print in one line the result of the operation. As the answer might be very large, please output the answer modulo 10^9+7
输入样例1:
5 51 1 1 1 1
u 1 3 1
q 1 5
u 3 5 1
q 3 3
q 1 5
输出样例1:
149
25
题意
给定一个长度为 n 的数组 q 次 询问
i) 选择 一段区间加上 x
ii) 输出一段区间的元素平方和
思路
一眼数据结构 线段树魔改下
定义原元素为 y 平方为 y^2
加上 x 后原元素变为了 y+x 平方为
y
2
+
2
x
y
+
x
2
y^2+2xy+x^2
y2+2xy+x2
对比可知即原元素 乘上 2x 再加上 x^2
平方和 更新为
y
2
(
原平分和
)
+
2
x
y
+
x
2
y^2(原平分和)+2xy+x^2
y2(原平分和)+2xy+x2
我们只需要在线段树数组里保存原元素的值用以更新平分和的值即可
故更新时应先更新平方和的值再更新原元素的值
取模细节多注意下 容易爆long long
Code
#include<bits/stdc++.h>
using namespace std;
int p;
struct segtree
{
long long v,vv,mul,add;
}st[400003];
long long a[100003];
void pushup(int rt)
{
st[rt].v=(st[rt<<1].v+st[rt<<1|1].v)%p;
st[rt].vv=(st[rt<<1].vv+st[rt<<1|1].vv)%p;
}
void build(int l,int r,int rt)
{
st[rt].mul=1;
st[rt].add=0;
if(l==r)
{
st[rt].v=a[l];
st[rt].vv=(a[l]*a[l])%p;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(int ln,int rn,int rt)
{
st[rt<<1].vv=((st[rt<<1].vv+2*st[rt].add*st[rt<<1].v%p+st[rt].add*st[rt].add%p*ln%p)%p+p)%p;
st[rt<<1|1].vv=((st[rt<<1|1].vv+2*st[rt].add*st[rt<<1|1].v%p+st[rt].add*st[rt].add%p*rn)%p+p)%p;
st[rt<<1].v=(st[rt<<1].v*st[rt].mul+st[rt].add*ln)%p;
st[rt<<1|1].v=(st[rt<<1|1].v*st[rt].mul+st[rt].add*rn)%p;
st[rt<<1].mul=(st[rt<<1].mul*st[rt].mul)%p;
st[rt<<1|1].mul=(st[rt<<1|1].mul*st[rt].mul)%p;
st[rt<<1].add=(st[rt<<1].add*st[rt].mul+st[rt].add)%p;
st[rt<<1|1].add=(st[rt<<1|1].add*st[rt].mul+st[rt].add)%p;
st[rt].mul=1;
st[rt].add=0;
}
long long ask(int al,int ar,int l,int r,int rt)
{
if(l>=al&&r<=ar)return st[rt].vv%p;
if(r<al||l>ar)return 0;
int m=(l+r)>>1;
pushdown(m-l+1,r-m,rt);
return (ask(al,ar,l,m,rt<<1)%p+ask(al,ar,m+1,r,rt<<1|1))%p;
}
void addupdate(int ul,int ur,long long d,int l,int r,int rt)
{
if(l>=ul&&r<=ur)
{
st[rt].vv=(((st[rt].vv+(2*d*st[rt].v)%p)%p+d*d%p*(r-l+1)%p)%p+p)%p;
st[rt].v=(st[rt].v+d*(r-l+1))%p;//v不能先更新,v^2更新依赖旧的v
st[rt].add=(st[rt].add+d)%p;
return;
}
int m=(l+r)>>1;
pushdown(m-l+1,r-m,rt);
if(m>=ul)addupdate(ul,ur,d,l,m,rt<<1);
if(ur>m)addupdate(ul,ur,d,m+1,r,rt<<1|1);
pushup(rt);
}
inline void sol()
{
int n,q;
scanf("%d%d",&n,&q);
p=1e9+7;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
}
build(1,n,1);
char cz;
int l,r;
long long x;
while(q--)
{
scanf(" %c%d%d",&cz,&l,&r);
if(cz=='u')
{
scanf("%lld",&x);
addupdate(l,r,x,1,n,1);
}
else
{
printf("%lld\n",ask(l,r,1,n,1));
}
}
}
int main()
{
sol();
return 0;
}