對於樹鏈剖分,看到大佬紛紛各種躺切內心很是惶恐,於是跪著請教大佬之後把自己的一點感悟發出來以防以後忘了qwq
指一種對樹進行劃分的演算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬於且只屬於一條鏈,然後再通過資料結構(樹狀陣列、sbt、splay、線段樹等)來維護每一條鏈常見的剖分的方法是輕重樹鏈剖分(也叫啟發式剖分)
·第一步是對樹進行輕重邊的劃分。
首先說一下什麼叫重邊
重邊:某個節點x到孩子節點形成的子樹中節點數最多的點child之間的邊,由定義發現除了葉子節點其他節點只有一條重邊·進一步剖分過程分為兩次dfs因此定義size[x]為以x為根的子樹節點個數,令v為u的兒子中size值最大的節點,那麼(u,v)就是重邊,其餘邊為輕邊。
第一次dfs就是找重邊,也就是記錄下所有的重邊。
程式具體操作:
首先記錄深度,更新父親,初始化兒子數,然後再在向外擴充套件時更新兒子數,按照定義記錄重兒子邊
·然後第二次dfs就是連線重邊形成重鏈這是一般的樹鏈剖分套路
對於本題來講in函式為插入一點,在處理求和dosum函式時要理解
過程是找同一條鏈,讓更深的往上跳,直到來到了一條鏈上,然後處理求和
另外陣列有點多,不好好看可能有點暈(¦3」∠)_(:з」∠)_
size陣列,用來儲存以x為根的子樹節點個數可以用二維陣列鄰接表鏈式前向星來表示邊,聽說用鄰接表or鏈式前向星來搞邊是比較好的,對於我主要還是對鏈式前向星比較熟悉emmmmmmtop陣列,用來儲存當前節點的所在鏈的頂端節點
son陣列,用來儲存重兒子
dep陣列,用來儲存當前節點的深度
fa陣列,用來儲存當前節點的父親
搞完了剖分基本就是套線段樹之類資料結構的來進一步實現搞事,這個嘛本蒟蒻需要繼續鑽研,不敢亂說23333
以codevs 2460 樹的統計為例(寫得醜不要嫌棄qwq)
附上乙份中間沒空格的樣例輸入
4輸出:1 2
2 3
4 1
4 2 1 3
12 qmax 3 4
qmax 3 3
qmax 3 2
qmax 2 3
qsum 3 4
qsum 2 1
change 1 5
qmax 3 4
change 3 6
qmax 3 4
qmax 2 4
qsum 3 4
4**如下:1 2
2 10
6 5
6 5
16
#include#include#include#define ls p<<1
#define rs p<<1|1
#define mid (shu[p].l+shu[p].r >>1)
#define ri register int
using namespace std;
const int sz = 300010;
int pos[sz],son[sz],top[sz],size[sz];
int dep[sz],fa[sz],fir[sz],nxt[sz];
int w[sz];
int tot,n,q,cnt,x,y,num;
char ch[15];
struct nodeshu[sz<<2];
struct edl[sz<<1];
inline void read(int &x)
while(ch >= '0' && ch <= '9')
if(flag)
x *= -1;
}inline void add(int f,int t)
; nxt[tot]=fir[f];
fir[f]=tot;
}inline void build(int p,int l,int r)
int midd = l+r>>1;
build(ls,l,midd);
build(rs,midd+1,r);
shu[p].sum=shu[ls].sum+shu[rs].sum;
shu[p].max=max(shu[ls].max,shu[rs].max);
}void dfs1(int k,int f,int d)
}void dfs2(int k,int tot)
}void in(int p,int x,int v)
if(x<=mid)
in(ls,x,v);
else
if(x>mid)
in(rs,x,v);
shu[p].sum=shu[ls].sum+shu[rs].sum;
shu[p].max=max(shu[ls].max,shu[rs].max);
}int qsum(int p,int l,int r)
int qmax(int p,int l,int r)
int dosum(int x,int y)
if(pos[x]>pos[y])
swap(x,y);
ans+=qsum(1,pos[x],pos[y]);
return ans;
}int domax(int x,int y)
if(pos[x]>pos[y])
swap(x,y);
ans=max(ans,qmax(1,pos[x],pos[y]));
return ans;
}int main()
else
}return
0;
}
筆記 樹鏈剖分
樹鏈剖分 對於每個結點 連線子節點多的那個子樹的邊叫做重邊 重邊連起來成鏈 叫重鏈 不止是只有一條重鏈 使用線段樹或者其他的資料結構存重鏈 用此資料結構進行操作 兩個dfs操作 第乙個dfs 求出重鏈 深度dep陣列 父節點fa陣列 和每個結點的子結點個數size陣列 知道了size才可以求出重鏈 ...
筆記 樹鏈剖分
洛谷 樹鏈剖分模板 前置芝士 鏈式前向星,線段樹,dfs序 這裡寫的是重鏈剖分。參考部落格指盜圖 x正義小學生x 樹鏈剖分可以把一棵樹 投影 到乙個序列上,然後用線段樹維護一些東西。通過重兒子的性質來保證時間複雜度。我們首先使用兩次dfs進行預處理,將樹投影到序列上。對於乙個有兒子的節點,我們定義它...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...