假设当前进行到操作 $m$.
1. 将区间 $[l,r]$ 每个数加上 $v$.
2. 询问当前区间 $[l,r]$ 的和.
3. 令 $S(l,r,x)$ 代表 $[l,r]$ 区间在时刻 $x$ 时之和,求 $sum_{i=0}^{m} S(l,r,i)$.
题解:
对于一个区间,我们要求当前区间和以及所有历史时刻之和.
考虑维护 $sum, sumh$ 分别表示当前和以及历史和.
如果没有加法标记,我们可以直接存一个 $tag$,表示 $sumh leftarrow sumh+tag imes sum.$
然后我们发现存在加法标记的情况下要先下传加法标记,再下传 $tag.$
考虑下传加法标记:
$sum leftarrow sum+len imes v$
$add leftarrow add+v$
$sumh leftarrow sumh+tag imes sum$.
对于点 $x$ 来说,假设原来有 $v1,tag1$,那么现在变为 $v1+v$,$tag1$.
而根据定义,$tag1$ 应该只和 $v1$ 结合,所有加多了一部分,那么就再设标记 $addh$ 表示 $sumh$ 需要减去的值就好了.
下传标记的顺序是:$add$,$addh$,$tag$.
code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100008
#define ll long long
#define lson now<<1
#define rson now<<1|1
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int a[N],n,m;
struct data {
int len;
ll sum,add,sumh,tag,addh;
}s[N];
void pushup(int now) {
s[now].sum=s[lson].sum+s[rson].sum;
s[now].sumh=s[lson].sumh+s[rson].sumh;
}
void mark_adh(int now,ll v,int t) {
s[now].addh+=v;
if(t) s[now].sumh+=v*s[now].len;
}
void mark_add(int now,ll v) {
if(s[now].tag) {
mark_adh(now,-v*s[now].tag,0);
}
s[now].add+=v;
s[now].sum+=1ll*s[now].len*v;
}
void mark_tag(int now,ll v) {
s[now].tag+=v;
s[now].sumh+=s[now].sum*v;
}
void pushdown(int now) {
if(s[now].add) {
mark_add(lson,s[now].add);
mark_add(rson,s[now].add);
s[now].add=0;
}
if(s[now].addh) {
mark_adh(lson,s[now].addh,1);
mark_adh(rson,s[now].addh,1);
s[now].addh=0;
}
if(s[now].tag) {
mark_tag(lson,s[now].tag);
mark_tag(rson,s[now].tag);
s[now].tag=0;
}
}
void build(int l,int r,int now) {
s[now].len=r-l+1;
if(l==r) {
s[now].sum=a[l];
s[now].sumh=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(now);
}
void update(int l,int r,int now,int L,int R,int v) {
if(l>=L&&r<=R) {
mark_add(now,v);
return;
}
pushdown(now);
int mid=(l+r)>>1;
if(L<=mid) update(l,mid,lson,L,R,v);
if(R>mid) update(mid+1,r,rson,L,R,v);
pushup(now);
}
ll query(int l,int r,int now,int L,int R) {
if(l>=L&&r<=R) {
return s[now].sumh;
}
pushdown(now);
int mid=(l+r)>>1;
ll re=0;
if(L<=mid) re+=query(l,mid,lson,L,R);
if(R>mid) re+=query(mid+1,r,rson,L,R);
return re;
}
int main() {
// setIO("input");
// freopen("de.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
}
build(1,n,1);
int x,y,z,l,r;
for(int i=1;i<=m;++i) {
scanf("%d%d%d",&l,&r,&x);
update(1,n,1,l,r,1ll*x);
mark_tag(1,1);
scanf("%d%d",&x,&y);
printf("%lld
",query(1,n,1,x,y));
}
return 0;
}
暴力:
#include <bits/stdc++.h>
#define N 1002
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll a[N][N],sum[N][N];
int main() {
setIO("input");
freopen("input.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld",&a[0][i]),sum[0][i]=a[0][i];
for(int i=1;i<=m;++i) {
int l,r,x,L,R;
scanf("%d%d%d",&l,&r,&x);
for(int j=1;j<=n;++j) a[i][j]=a[i-1][j];
for(int j=l;j<=r;++j) a[i][j]+=1ll*x;
for(int j=1;j<=n;++j) sum[i][j]=sum[i-1][j]+a[i][j];
scanf("%d%d",&L,&R);
ll s=0;
for(int j=L;j<=R;++j) s+=sum[i][j];
printf("%lld
",s);
}
return 0;
}
/*
input:
5 3
1 2 3 4 5
1 1 1 2 4
1 3 2 2 4
1 3 3 1 5
output:
18
31
84
*/
数据生成器及对拍:
#include <bits/stdc++.h>
using namespace std;
int RAN(int p) { return rand()%p+1; }
void make() {
FILE *fp=fopen("input.in","w");
int n=1000,m=1000;
fprintf(fp,"%d %d
",n,m);
for(int i=1;i<=n;++i) {
fprintf(fp,"%d ",RAN(1000));
}
fprintf(fp,"
");
for(int i=1;i<=m;++i) {
int l=RAN(n),r=RAN(n);
if(l>r) swap(l,r);
fprintf(fp,"%d %d %d ",l,r,RAN(1000));
int L=RAN(n),R=RAN(n);
if(L>R) swap(L,R);
fprintf(fp,"%d %d
",L,R);
}
fclose(fp);
}
void gen() {
make();
}
int main() {
system("g++ std.cpp -o std.exe -g -O2 -std=c++11 -Wl,-stack=512000000");
system("g++ code.cpp -o code.exe -g -O2 -std=c++11 -Wl,-stack=512000000");
srand(time(NULL));
rand();
int times=0;
while(1) {
gen();
system("std.exe < input.in > de.out");
int s=clock();
system("code.exe < input.in > input.out");
int t=clock();
if(system("fc input.out de.out > FC.out")) {
printf("WA
");
break;
}
else {
printf("%d : AC : %d
",++times,t-s);
}
}
return 0;
}