deep:記錄該節點的深度
siz:記錄以該節點為根的子樹的節點數
fa:記錄該節點的父親是誰
son:記錄該節點的重兒子是誰
top:記錄該節點所在的重鏈的根節點是誰
w:記錄該節點投影到數軸後的位置(即dfs序,線段樹要用)
讀入,用空間池儲存邊(注意是雙向的);
第一次dfs:
記錄dep,siz,fa,son(找siz最大的兒子做重兒子)
第二次dfs:
記錄w;
順著son處理重鏈記錄top(包括自己)
之後處理輕鏈
【偽**】
設現處理x節點,其重父親為tp
dfs2(x,tp)
time++;
w[x]=time;
top[x]=tp;
if(有重兒子)
建線段樹
修改:從x到y的節點加d
while(top[x]!=top[y])
if(dep[x] > dep[y]) swap(x,y);
insert(1,1,n,w[x],w[y],d);
6.查詢(和線段樹一樣就不說了)
貼個**吧,hdu3966,比較經典的樹剖題
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define zero(a) memset(a,0,sizeof(a))
#define minus(a) memset(a,-1,sizeof(a))
const
int max_n = 50100;
struct edgee[max_n * 3];
int siz[max_n];
int dep[max_n];
int fa[max_n];
int son[max_n];
int top[max_n];
int w[max_n];
int a[max_n];
int h[max_n];
int n,m,q,ep,time;
int cnt[max_n * 4];
inline
void add(int x,int y)
void dfs1(int x,int fat,int deep)
return;
}void dfs2(int x,int tp)
}return;
}void insert(int rt,int l,int r,int a,int b,int val)
int lson = rt*2;
int rson = rt*2+1;
int mid = (l+r)/2;
insert(lson,l,mid,a,b,val);
insert(rson,mid+1,r,a,b,val);
return;
}inline
void revise(int x,int y,int d)
if(dep[x] > dep[y]) swap(x,y);
insert(1,1,n,w[x],w[y],d);
return;
}int query(int rt,int l,int r,int idx,int sum)
inline
void ask(int x)
inline
void init()
inline
void read()
return;
}inline
void build()
inline
void solve()
scanf("%d %d %d",&x,&y,&d);
if(c[0]=='d')
d=-d;
revise(x,y,d);
}return;
}int main()
return
0;}
樹鏈剖分基本步驟
總體步驟 init dfs1 1 dfs2 1,1 build 1,1,n cl dfs1 處理出size sj 子節點數 son sj 重兒子 dep sj 深度 vi sj 點權,把邊權放在子節點上 dfs2 處理出top sj 所在鏈的鏈首,輕兒子從子節點重新開始,重兒子從父節點繼承 id s...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...
樹鏈剖分 樹剖換根
這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...