牛客网练习赛t2(线段树)
题解:
好像因为他说了
数据范围全部在ll以内
所以直接暴力就可以过了
比较正常是用线段树来维护
洛谷上有道模板题是支持加,乘,区间和
而这题还多了区间平方和的操作
按照那题的操作
我们维护的时候保证先乘再加
a1^2+a2^2+a3^2
我们考虑先*x再+y 以及先+y再*x两种操作
(a1*x+y)^2+(a2*x+y)^2+(a3*x+y)^2
x*x*(a1+y)^2
于是我们维护操作的时候是这样的
平方和+=2*sum1*乘法标记*lazy值+乘法标记*乘法标记*lazy值
关键在于这个2*sum1*乘法标记*lazy值
看第一种情况展开项为2*a1*x*y 符合
第二种情况为2*x*x*a1*y 而这个我们已经对y乘了x 所以也是对的
代码:
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define ll long long #define mid ((h+t)/2) const int N=2e4; int a[N],n,m; struct sgt{ ll sum[N*4],sum2[N*4],lazy[N*4]; ll lazy3[N*4]; sgt() { rep(i,0,N*4-1) lazy3[i]=1; } IL void updata(int x) { sum[x]=sum[x*2]+sum[x*2+1]; sum2[x]=sum2[x*2]+sum2[x*2+1]; } IL void down(int x,int h,int t) { ll t1=sum[x*2],t2=sum[x*2+1],t3=lazy3[x]; if (lazy3[x]!=1) { sum[x*2]*=lazy3[x]; sum[x*2+1]*=lazy3[x]; sum2[x*2]*=lazy3[x]*lazy3[x]; sum2[x*2+1]*=lazy3[x]*lazy3[x]; lazy3[x*2]*=lazy3[x]; lazy3[x*2+1]*=lazy3[x]; lazy[x*2]*=lazy3[x]; lazy[x*2+1]*=lazy3[x]; lazy3[x]=1; } sum2[x*2]+=2*t1*lazy[x]*t3+(mid-h+1)*lazy[x]*lazy[x]; sum2[x*2+1]+=2*t2*lazy[x]*t3+(t-mid)*lazy[x]*lazy[x]; if (lazy[x]) { sum[x*2]+=(mid-h+1)*lazy[x]; sum[x*2+1]+=(t-mid)*lazy[x]; lazy[x*2]+=lazy[x]; lazy[x*2+1]+=lazy[x]; lazy[x]=0; } } void build(int x,int h,int t) { if (h==t) { sum[x]=a[h]; sum2[x]=a[h]*a[h]; return; } build(x*2,h,mid); build(x*2+1,mid+1,t); updata(x); } void add(int x,int h,int t,int h1,int t1,ll k) { if (h1<=h&&t<=t1) { lazy[x]+=k; sum2[x]=sum2[x]+2*k*sum[x]+(t-h+1)*k*k; sum[x]=sum[x]+(t-h+1)*k; return; } down(x,h,t); if (h1<=mid) add(x*2,h,mid,h1,t1,k); if (mid<t1) add(x*2+1,mid+1,t,h1,t1,k); updata(x); } void change(int x,int h,int t,int h1,int t1,ll k) { if (h1<=h&&t<=t1) { lazy[x]*=k;lazy3[x]*=k; sum2[x]=sum2[x]*k*k; sum[x]=sum[x]*k; return; } down(x,h,t); if (h1<=mid) change(x*2,h,mid,h1,t1,k); if (mid<t1) change(x*2+1,mid+1,t,h1,t1,k); updata(x); } ll query1(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) return(sum[x]); ll ans=0; down(x,h,t); if (h1<=mid) ans+=query1(x*2,h,mid,h1,t1); if (mid<t1) ans+=query1(x*2+1,mid+1,t,h1,t1); return(ans); } ll query2(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) return(sum2[x]); ll ans=0; down(x,h,t); if (h1<=mid) ans+=query2(x*2,h,mid,h1,t1); if (mid<t1) ans+=query2(x*2+1,mid+1,t,h1,t1); return(ans); } }S; int main() { ios::sync_with_stdio(false); cin>>n>>m; rep(i,1,n) cin>>a[i]; S.build(1,1,n); rep(i,1,m) { int kk,x1,x2,y; cin>>kk; if (kk==1) { cin>>x1>>x2; cout<<S.query1(1,1,n,x1,x2)<<endl; } if (kk==2) { cin>>x1>>x2; cout<<S.query2(1,1,n,x1,x2)<<endl; } if (kk==3) { cin>>x1>>x2>>y; S.change(1,1,n,x1,x2,y); } if (kk==4) { cin>>x1>>x2>>y; S.add(1,1,n,x1,x2,y); } } return 0; }