樹鏈剖分學習筆記

2021-08-25 14:24:08 字數 1977 閱讀 1077

寫**又犯了很sb的錯誤,線段樹寫錯了。。。

好像每次都會把r-l+1寫成l-r+1,然後就只有20分。。。

**寫的比較醜,壓了壓之後190行。。。

基本上是我打過的最長的乙個模板了

然後簡單介紹一下樹剖吧。。。

樹鏈剖分,就是把樹剖分成鏈,然後用資料結構來維護這些鏈,使得詢問、修改的複雜度達到o(

logn

) o(l

ogn)

(不會證明。。。)

幾個定義:

這樣我們就可以利用這個性質來把樹上的修改、查詢問題轉化成區間問題,就可以用樹狀陣列、線段樹等資料結構來維護,進行修改、查詢等操作

當然其中也包含lca問題,這裡並不是用倍增求的lca,而是用剖分好的鏈來求的

好像這樣剖分時間複雜度會比較***,但是我並不會證明。。。好弱啊。。。

還有一些小細節問題,可以看**

我是看這裡學的樹剖:

#include 

#include

#include

#include

#include

#define for(i,l,r) for(int i=l;i<=r;++i)

#define mid ((l+r)>>1)

#define ls (x<<1)

#define rs ((x<<1)|1)

#define maxn 100010

using namespace std;

inline int

read()

while(isdigit(c))

return a*(t?-1:1);

}struct edgee[maxn*2];

int n,m,root,p,cnt;

int v[maxn],last[maxn],fa[maxn],dep[maxn],tid[maxn],dfs[maxn],son[maxn],top[maxn],size[maxn];

int lazy[maxn*4],sum[maxn*4],ans;

void dfs1(int now,int fat,int depth)

temp=e[temp].next;

}}void dfs2(int now,int t)

}void build(int l,int r,int

x) else

}void down(int l,int r,int

x)void modify(int l,int r,int

x,int ll,int rr,int k)

else

}void ask(int l,int r,int

x,int ll,int rr)//線段樹詢問

else

}void query(int

x,int

y)//

else

}if(dfs[x]<=dfs[y])ask(1,n,1,dfs[x],dfs[y]);

else ask(1,n,1,dfs[y],dfs[x]);

printf("%d\n",ans);

}void update(int

x,int

y,int z)

else

}if(dfs[x]<=dfs[y])

modify(1,n,1,dfs[x],dfs[y],z);

else

modify(1,n,1,dfs[y],dfs[x],z);

}void add(int from,int to)

int main()

dfs1(root,0,1);cnt=0;dfs2(root,root);build(1,n,1);

for(i,1,m)

else

if(tx==2)

else

if(tx==3)

else

}return

0;}

樹鏈剖分學習筆記

樹鏈剖分 mod estc oder modestcoder modest code r如果你是重兒子,你就在重路徑上。如果你是輕兒子,暴力沿著祖先向上爬最多log nlogn logn 次就可以遇到重路徑。或者到根 而樹上操作基本就是找祖先 也許有人喜歡我的碼風 include include d...

樹鏈剖分學習筆記

前言 書上只講了重鏈剖分,菜雞也只會這一種,想看其他的是別想了。要會樹鏈剖分,首先你需要了解一些概念。我們把乙個節點的所有兒子節點中子樹節點數最大的稱為重兒子,也就是size最大的子節點。size的定義我在講換根dp時說過,因此不再贅述。對於每個節點的重兒子,我們用 son x 來記錄它,父親節點到...

樹鏈剖分 學習筆記

前置知識 dfs 序,線段樹 我們可以回顧兩個問題 1.樹上從 s 到 t 的路徑,每個點權值加上 z 很簡單。遍歷整棵樹即可。2.求樹上 s 到 t 的權值和。lca 可做。可以利用 lca 的性質 dis s dis t 2 dis lca 做即可。時間複雜度 o n log n 但是把這兩個問...