题意:
给你一个数组,然后有两种操作,一种操作是让l到r都加上x,另一种是查询l,r的值,这个值的定义是
思考:
其实看起来这个式子很复杂,实际上看看就是对于l到r中的每个数,都乘以他后面的数,这不就是l到r区间内的数两两相乘吗。但是这怎么去维护呢,有个公式就是,区间内任意两个数相乘=(区间和的平方-区间平方的和)/2。所以就用线段树去维护区间和,然后区间平方的和怎么弄呢,其实就是比如aa+bb,如果都加x,那么就是(a+x)(a+x)+(b+x)(b+x)=aa+bb+xx2+2x(a+b),很明显了就是ans+区间长度xx+区间和2x。
代码:
const int N = 2e5+5,M = 2000;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const double pai = acos(-1);
struct Node{
int L,R;
int laz;
int sum;
int ans;
}t[4*N];
int T,n,m,k;
int va[N];
void pushup(int node)
{
t[node].sum = t[node_l].sum+t[node_r].sum;
t[node].ans = t[node_l].ans+t[node_r].ans;
}
void pushdown(int node)
{
int laz = t[node].laz;
if(laz)
{
t[node_l].laz += laz;
t[node_l].ans += (t[node_l].R-t[node_l].L+1)*laz*laz+2*t[node_l].sum*laz;
t[node_l].sum += (t[node_l].R-t[node_l].L+1)*laz;
t[node_r].laz += laz;
t[node_r].ans += (t[node_r].R-t[node_r].L+1)*laz*laz+2*t[node_r].sum*laz;
t[node_r].sum += (t[node_r].R-t[node_r].L+1)*laz;
t[node].laz = 0;
}
}
void build(int node,int l,int r)
{
t[node].L = l,t[node].R = r;
if(l==r)
{
t[node].sum = va[l];
t[node].ans = va[l]*va[l];
return ;
}
int mid = l+r>>1;
build(node_l,l,mid);build(node_r,mid+1,r);
pushup(node);
}
void update(int node,int l,int r,int value)
{
if(t[node].L>=l&&t[node].R<=r)
{
t[node].ans += (t[node].R-t[node].L+1)*value*value+2*t[node].sum*value;
t[node].sum += (t[node].R-t[node].L+1)*value;
t[node].laz += value;
return ;
}
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(l<=mid) update(node_l,l,r,value);
if(r>mid) update(node_r,l,r,value);
pushup(node);
}
int query1(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r) return t[node].sum;
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) return query1(node_l,l,r);
else if(l>mid) return query1(node_r,l,r);
else return query1(node_l,l,mid)+query1(node_r,mid+1,r);
}
int query2(int node,int l,int r)
{
if(t[node].L>=l&&t[node].R<=r) return t[node].ans;
pushdown(node);
int mid = (t[node].L+t[node].R)>>1;
if(r<=mid) return query2(node_l,l,r);
else if(l>mid) return query2(node_r,l,r);
else return query2(node_l,l,mid)+query2(node_r,mid+1,r);
}
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>va[i];
build(1,1,n);
while(m--)
{
int op,a,b,c;
cin>>op;
if(op==1)
{
cin>>a>>b>>c;
update(1,a,b,c);
}
else
{
cin>>a>>b;
int t1 = query1(1,a,b),t2 = query2(1,a,b);
int anw = (t1*t1-t2)/2;
cout<<anw<<"\n";
}
}
return 0;
}
总结:
多多尝试,多多推推式子不要畏惧。