bzoj4034 T2 樹鏈剖分 樹狀陣列

2021-07-10 12:04:09 字數 1185 閱讀 6617

一種明顯的做法是直接樹鏈剖分然後用區間修改區間查詢樹狀陣列(我寫的這種)或者線段樹來維護吧。。這樣做是o(nlog^2n)的。

但是還可以做到o(nlogn)。首先可以發現它是單點鏈上查詢,那麼可以考慮用差分的思想,或者考慮將單點修改直接變成區間修改然後就只用單點簡單查詢了。

首先考慮單點修改,這種操作只對它所在的子樹中的所有點的答案有影響,也就是所在的子樹中每乙個點的答案+a,這個可以用dfs序列轉化為區間修改。

然後考慮對子樹x的修改,那麼對所在的子樹中某乙個點p,點p的答案+a*(d[p]-d[x]+1)=+a*d[p]+(a-a*d[x]),注意到括號中的部分是常數(即對每乙個p來說相同),用上面的單點修改即可。然後我們還需要乙個陣列b(另外乙個假設是a)維護每乙個點的d[p]被加上了多少次。這樣還是區間修改。

那麼查詢的答案就是ai+bi*d[i]了,直接上查分的樹狀陣列轉化為單點修改字首查詢。o(nlogn),這個應該是最快的寫法了。

ac**如下(樹鏈剖分+區間修改區間查詢樹狀陣列):

#include#include#include#define ll long long

#define n 100005

using namespace std;

int n,m,tot,dfsclk,a[n],fst[n],pnt[n<<1],nxt[n<<1],bg[n],ed[n],fa[n],anc[n],son[n],sz[n];

ll c[2][n];

int read()

while (ch>='0' && ch<='9')

return x*fu;

}void add(int x,int y)

void ins(int k,int x,ll t)

ll getsum(int k,int x)

void mdy(int x,int y,ll z)

ll qry(int x,int y)

void dfs(int x) }}

void divide(int x,int tp)

ed[x]=dfsclk;

}int main(){

n=read(); m=read(); int i,k,x,y; ll ans;

for (i=1; i<=n; i++) a[i]=read();

for (i=1; i

by lych

2016.3.14

BZOJ 4034 T2 樹鏈剖分解決子樹問題

樹鏈剖分有這樣乙個性質,即在剖完之後每個結點下面子樹的編號一定是連續的,那麼基於這一點,我們記錄每個結點的區間就能解決子樹更新問題 dfs序也可以解決子樹問題,但是這裡需要計算乙個貢獻值,結點的層數不好處理。include include include includeusing namespace...

bzoj4034 樹鏈剖分

time limit 10 sec memory limit 256 mb submit 7576 solved 2597 submit status discuss 有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作...

11 03T2 樹鏈剖分

給你一棵樹,每次詢問樹上兩條鏈是否有交點。第一行n,表示n個結點 第二行開始n 1行倆個 數x y,表示x,y有一條邊 接下來q,表示q個詢問 接下來q行四個數a b c d,詢問a到b的鏈是否與c到d的鏈有交點 輸出q行 yes或no sample input 輸入1 1 21 3 2 42 5 ...