线段树历史版本和

假设当前进行到操作 $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 \times sum.$       

然后我们发现存在加法标记的情况下要先下传加法标记,再下传 $tag.$    

考虑下传加法标记:

$sum \leftarrow sum+len \times v$  

$add \leftarrow add+v$

$sumh \leftarrow sumh+tag \times 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\n",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\n",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",n,m);  
    for(int i=1;i<=n;++i) {
        fprintf(fp,"%d ",RAN(1000));   
    }
    fprintf(fp,"\n");   
    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\n",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\n");   
            break; 
        } 
        else {   
            printf("%d : AC : %d\n",++times,t-s);  
        }
    }
    return 0; 
}

  

 

  

posted @ 2020-07-09 16:09  EM-LGH  阅读(1875)  评论(1编辑  收藏  举报