分析一下
首先分析这道题之前先看这道题:(看视频!!!)
https://www.acwing.com/problem/content/1279/
-
明确要维护哪些信息?
l,r,sum,add,mul -
如何维护信息:
(1)考虑pushup时的维护:这个简单,tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;(2)考虑懒标记的维护(add和mul): 此时就要考虑 懒标记的优先级的问题 和 懒标记之间的影响 1)懒标记的优先级的问题: 若先+再x,则(v+add)*mul要+add'时不好维护; 若先x再+,(v*mul+add) +add'时(v*mul+add+add') *mul'时(v*mul*mul'+add*mul') 可以维护 2)懒标记之间的影响: (v*mul+add) *mul'时:mul -> mul*mul',add -> add*mul' +add'时:mul不变,add -> add+add' (3)考虑pushdown时 和 打懒标记时 当前区间的信息维护 如果+x,v1+v1 -> v1+v1+2*x; 如果*x,v1+v2 -> (v1+v2)*x;
回到这个题上,这个题就是多维护个区间平方和就行,其他是一样的;
如何维护区间平方和:
(1)考虑pushup时的维护:这个简单,tr[u].sum_vv = tr[u<<1].sum_vv + tr[u<<1|1].sum_vv;
(2)考虑pushdown时 和 打懒标记时 当前区间的信息维护:
如果此时sum = v1^2 + v2^2
若+x:带入拆开后sum' = v1^2 + v2^2 + 2x^2 + 2*v1*x + 2*v2*x;
即tr[u].sum_vv += ((tr[u].r - tr[u].l + 1) * x * x + tr[u].sum_v * 2 * x);
若*x:sum' = (v1^2 + v2^2) * x^2
即tr[u].sum_vv *= (x*x);
注意到在+x时要用到tr[u].sum_v,所以我们要先更新区间平方和;
而且注意mul的初始化是1
代码
#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
#include<stdio.h>
#include<map>
#include<algorithm>
#include<deque>
#include<stack>
#include<set>
#include <unordered_map>
#include<math.h>
#include<string.h>
#define IOS ios::sync_with_stdio(false),cin.tie(0);
using namespace std;
#define pb push_back
#define coutl cout<<"------------"<<endl;
#define fi first
#define se second
#define ire(x) scanf("%d",&x)
#define iire(a,b) scanf("%d %d",&a,&b)
#define lre(x) scanf("%lld",&x)
#define llre(a,b) scanf("%lld %lld",&a,&b)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define endl "\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<ll, ll> PLL;
typedef pair<double, double> PDD;
typedef pair<double, pair<int, double>> PDID;
typedef pair<char, char> PCC;
typedef pair<char, pair<int, int> > PCII;
typedef pair<int, pair<int, int> > PIII;
typedef pair<int, pair<int, pair<int, int> > > PIIII;
typedef pair<ll, pair<int, int> > PLII;
const int maxn = 1e6 + 7;
const int N = 2010 + 7;
const int M = 1e6 + 7;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1);
const double eps = 1e-8;
ll gcd(ll a,ll b) {return b==0 ? a : gcd(b,a%b);}
ll lcm(ll a,ll b) {return a*b / gcd(a,b);}
ll qmi(ll a,ll b,ll p) {ll ans = 1; while(b) { if(b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans;}
int lowbit(int x) {return x & (-x);}
int a[maxn];
int n,m;
struct node
{
int l,r;
ll sum_v,sum_vv;
ll add,mul;
}tr[maxn];
void pushup(int u)
{
tr[u].sum_v = tr[u<<1].sum_v + tr[u<<1|1].sum_v;
tr[u].sum_vv = tr[u<<1].sum_vv + tr[u<<1|1].sum_vv;
}
void pushdown(int u)
{
//先传mul,再传add
if(tr[u].mul)
{
tr[u<<1].add *= tr[u].mul;
tr[u<<1].mul *= tr[u].mul;
tr[u<<1].sum_v *= tr[u].mul;
tr[u<<1].sum_vv *= (tr[u].mul * tr[u].mul);
tr[u<<1|1].add *= tr[u].mul;
tr[u<<1|1].mul *= tr[u].mul;
tr[u<<1|1].sum_v *= tr[u].mul;
tr[u<<1|1].sum_vv *= (tr[u].mul * tr[u].mul);
tr[u].mul = 1; //清空懒标记
}
if(tr[u].add) //先更新区间平方和,再更新区间和
{
tr[u<<1].add += tr[u].add;
tr[u<<1].sum_vv += ((tr[u<<1].r - tr[u<<1].l + 1) * tr[u].add * tr[u].add + tr[u<<1].sum_v * 2 * tr[u].add);
tr[u<<1].sum_v += (tr[u<<1].r - tr[u<<1].l + 1) * tr[u].add;
tr[u<<1|1].add += tr[u].add;
tr[u<<1|1].sum_vv += ((tr[u<<1|1].r - tr[u<<1|1].l + 1) * tr[u].add * tr[u].add + tr[u<<1|1].sum_v * 2 * tr[u].add);
tr[u<<1|1].sum_v += (tr[u<<1|1].r - tr[u<<1|1].l + 1) * tr[u].add;
tr[u].add = 0;
}
}
void build(int u,int l,int r)
{
if(l == r)
{
tr[u] = {l,r,a[l],a[l]*a[l],0,1};
return ;
}
tr[u] = {l,r};
int mid = l + r >> 1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
void update1(int u,int l,int r,int x) //区间+x
{
if(l > r) return;
if(tr[u].l >= l && tr[u].r <= r) //打懒标记
{
//注意add是没有包括自己区间的哦
//先更新sum_vv再更新sum_v
tr[u].sum_vv += ((tr[u].r - tr[u].l + 1) * x * x + tr[u].sum_v * 2 * x);
tr[u].sum_v += (tr[u].r - tr[u].l + 1) * x;
tr[u].add += x;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) update1(u<<1,l,r,x);
if(r > mid) update1(u<<1|1,l,r,x);
pushup(u);
}
void update2(int u,int l,int r,int x) //区间*x
{
if(l > r) return;
if(tr[u].l >= l && tr[u].r <= r) //打懒标记
{
//注意add是没有包括自己区间的哦
tr[u].sum_v *= x;
tr[u].sum_vv *= (x*x);
tr[u].mul *= x;
tr[u].add *= x;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) update2(u<<1,l,r,x);
if(r > mid) update2(u<<1|1,l,r,x);
pushup(u);
}
ll query(int u,int l,int r,int p) //查询区间和
{
if(tr[u].l >= l && tr[u].r <= r)
{
if(p == 1) return tr[u].sum_v;
else return tr[u].sum_vv;
}
pushdown(u); //分裂了,下传懒标记
int mid = tr[u].l + tr[u].r >> 1;
ll sum = 0;
if(l <= mid) sum += query(u<<1, l, r, p);
if(r > mid) sum += query(u<<1|1, l, r, p);
return sum;
}
int main()
{
iire(n,m);
for(int i=1;i<=n;i++) ire(a[i]);
build(1,1,n);
while(m--)
{
int op;
ire(op);
if(op == 1) //查询区间和
{
int l,r;
iire(l,r);
cout<<query(1,l,r,1)<<endl;
}
else if(op == 2) //查询区间平方和
{
int l,r;
iire(l,r);
cout<<query(1,l,r,2)<<endl;
}
else if(op == 3) //区间*x
{
int l,r,x;
iire(l,r); ire(x);
update2(1,l,r,x);
}
else //区间+x
{
int l,r,x;
iire(l,r); ire(x);
update1(1,l,r,x);
}
}
return 0;
}