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

2021-10-05 14:20:33 字數 3587 閱讀 4270

題意:乙個多重集合的價值為將其變為公差為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′>r,l

ll使得[l,

r]

[l,r]

[l,r

]是最長的可以實現的區間,l′l'

l′是使得[l′

,r′]

[l',r']

[l′,r′

]是最長的可以實現的區間,那麼l′≥

ll' \geq l

l′≥l

,所以我們可以用雙指標掃一遍求出所有可以實現的區間在哪些區間內。

那麼對於所有可以實現的區間,我們有乙個簡單的方法可以計算乙個區間[l,

r]

[l,r]

[l,r

]構成的集合的價值:

最 大值

d−最小

值d+l

−r

\frac d - \frac d + l - r

d最大值​−

d最小值

​+l−

r l,

r]

[l,r]

[l,r

]的價值,離線後就是雙指標右端點到達r

rr時,單點查詢lll.

如果問的是∑i=

lr[i

,r

]\sum_^r [i,r]

∑i=lr​

[i,r

]的價值,那麼就是區間查詢l,r

l,rl,

r可是我們詢問的是∑i=

lr∑j

=ir[

i,j]

\sum_^r \sum_^r [i,j]

∑i=lr​

∑j=i

r​[i

,j]的價值和。

這就意味著我們在右端點是r

rr的時候還需要統計到右端點是r

−1...

r-1...

r−1...

的答案。

所以我們假設右端點在i

ii的時候就是我們線段樹的第i

ii個版本。

那麼我們相當於就是要求線段樹的歷史版本區間和hsu

mhsum

hsum

。需要增加乙個標記tag

tagta

g,這個標記的意義是:

當乙個區間打上tag

+=

vtag += v

tag+=v

時,h su

m+=s

um∗v

hsum += sum * v

hsum+=

sum∗

v。然後在之後下放給兒子。

考慮這個標記會和區間加add

addad

d標記有不良互動。於是我們讓乙個區間在同時有add

addad

d和ta

gtag

tag時先下放add

addad

d再下放tag

tagta

g。那麼在乙個有add

addad

d的點上打tag

tagta

g不會影響先後順序,沒有問題。但是反過來在有tag

tagta

g的點上打add

addad

d後下放這個點的標記就會造成前後顛倒。

那麼就把多加的hsu

mhsum

hsum

減回去,新加乙個標記add

haddh

addh

,當乙個區間打上add

h+=v

addh+= v

addh+=

v時,hsu

m+=l

en∗v

hsum += len * v

hsum+=

len∗

v。然後在之後下放給兒子,這裡的len是這個區間的長度。

那麼就結束了。

a cc

od

e\rm ac \ code

accode

#include

#define maxn 300005

#define f first

#define s second

#define mp make_pair

#define pii pair

#define ll long long

#define lc u<<1

#define rc lc|1

using

namespace std;

int n,d,q,s[maxn]

;vectorg[maxn]

;ll sm[maxn<<3]

,hsm[maxn<<3]

,ad[maxn<<3]

,adh[maxn<<3]

,len[maxn<<3]

,had[maxn<<3]

;void

dtp2

(int u,

int v)

void

dtp3

(int u,ll v,

int t=1)

void

dtp1

(int u,

int v)

voiddt(

int u)

void

add(

int u,

int l,

int r,

int ql,

int qr,

int v)

void

pud(

int u,

int l,

int r,

int ql,

int qr)

ll qry

(int u,

int l,

int r,

int ql,

int qr)

void

build

(int u,

int l,

int r)

int st[2]

[maxn]

,qr[2]

;int cd[

10000007

],scd,usd[

10000007

],sud;

ll ans[maxn]

;int

main()

build(1

,1,n);

for(

int i=

1,j=

1;i<=n;i++

)for

(int i=

1;i<=q;i++

)printf

("%lld\n"

,ans[i]);

}

線段樹 維護序列

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為 n 的數列,不妨設為 a1,a2,an。有如下三種操作形式 把數列中的一段數全部乘乙個值 把數列中的一段數全部加乙個值 詢問數列中的一段數的和,由於答案可能很大,你只需輸出這個數模 p 的值。輸入格式 第一行兩個整數 n 和 p ...

線段樹 GD SGOI 公路維護

用線段樹維護區間沒有被損壞的路的最小值,最小值對應的下標,區間被損壞的路的個數。標記下穿的時候先傳add,再傳mark,傳add的時候minv,add,mark都要加上add o 傳mark的時候,minv,mark都要取最大。include include include include incl...

線段樹 I 維護序列

老師交給小可可乙個維護數列的任務,現在小可可希望你來幫他完成。有長為 nn 的數列,不妨設為 a1,a2,ana1,a2,an。有如下三種操作形式 input 第一行兩個整數 nn 和 pp 第二行含有 nn 個非負整數,從左到右依次為 a1,a2,ana1,a2,an 第三行有乙個整數 mm,表示...