線段樹歷史版本和

2021-10-08 01:32:14 字數 2813 閱讀 1356

假設當前進行到操作 $m$.     

1. 將區間 $[l,r]$ 每個數加上 $v$.   

2. 詢問當前區間 $[l,r]$ 的和.  

3. 令 $s(l,r,x)$ 代表 $[l,r]$ 區間在時刻 $x$ 時之和,求 $\sum_^ 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 #include #include #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 s[n];

void pushup(int now)

void mark_adh(int now,ll v,int t)

void mark_add(int now,ll v)

s[now].add+=v;

s[now].sum+=1ll*s[now].len*v;

} void mark_tag(int now,ll v)

void pushdown(int now)

if(s[now].addh)

if(s[now].tag)

}void build(int l,int r,int now)

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)

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)

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()

build(1,n,1);

int x,y,z,l,r;

for(int i=1;i<=m;++i)

return 0;

}

暴力: 

#include #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()

return 0;

}

/*

input:

5 31 2 3 4 5

1 1 1 2 4

1 3 2 2 4

1 3 3 1 5

output:

1831

84

*/

資料生成器及對拍:  

#include using namespace std;    

int ran(int p)

void make()

fprintf(fp,"\n");

for(int i=1;i<=m;++i)

fclose(fp);

}void gen()

int main()

else

}return 0;

}

Arithmetic(線段樹維護歷史版本和)

題意 乙個多重集合的價值為將其變為公差為d dd 將在第一行輸入 的等差數列需要插入幾個數字 無法實現價值為0 多次詢問l,r l,rl,r,求 l,r l,r l,r 的子區間的價值和。序列長度3e5 3e53e 5,數字大小和d 1 e7 d leq 1e7 d 1e7 首先對於r rr r r...

ZKW線段樹 非遞迴版本的線段樹

學習和參考 下面是支援區間修改和區間查詢的zkw線段樹模板,先記下來。include include include include include include include include include include include include include include inc...

線段樹和zkw線段樹

好啦,我們就開始說說線段樹吧 線段樹是個支援區間操作和查詢的東東,平時的話還是蠻實用的 下面以最基本的區間加以及查詢區間和為例 線段樹顧名思義就是棵樹嘛,葉子節點是每個基本點,它們所對應的父親就是它們的和,具體如下圖 但是對於這樣的線段樹來說,操作所需的時間是遠達不到我們的要求的 會被t 因為我們會...