這幾天學習了一下樹鏈剖分,順便寫一下我的理解、
早上看了一下別人的講解,雲裡霧裡,終於算是搞懂了、
重邊:某個節點x到孩子節點形成的子樹中節點數最多的點child之間的邊,由定義發現除了葉子節點其他節點只有一條重邊
重邊是可以放在一塊兒更新的,而有
性質:從根到某一點的路徑上輕邊、重邊的個數都不大於logn。
所以這樣查詢的時間複雜度相當於log2(n)
其實樹鏈剖分就是把邊雜湊到線段樹上的資料結構。
實現的話很簡單,用兩個dfs處理數數的資訊,重邊以及輕邊,然後就是一些線段樹的操作了。
模板「:以spoj 375 為例
#include
#include
#include
#include
using
namespace
std;
#define del(a,b) memset(a,b,sizeof(a))
const
int n = 10005;
int dep[n],siz[n],fa[n],id[n],son[n],val[n],top[n]; //top 最近的重鏈父節點
int num;
vector
v[n];
struct tree
};tree e[n];
void dfs1(int u, int f, int d)
}void dfs2(int u, int tp)
}#define lson(x) ((x<<1))
#define rson(x) ((x<<1)+1)
struct tree
;tree tree[4*n];
void pushup(int x)
void build(int l,int r,int v)
int mid=(l+r)>>1;
build(l,mid,v*2);
build(mid+1,r,v*2+1);
pushup(v);
}void update(int o,int v,int val) //log(n)
int mid = (tree[o].l+tree[o].r)/2;
if(v<=mid)
update(o*2,v,val);
else
update(o*2+1,v,val);
pushup(o);
}int query(int x,int l, int r)
int mid = (tree[x].l + tree[x].r) / 2;
int ans = 0;
if (l <= mid) ans = max(ans, query(lson(x),l,r));
if (r > mid) ans = max(ans, query(rson(x),l,r));
return ans;
}int yougth(int u, int v)
ans = max(query(1,id[tp1], id[u]), ans);
u = fa[tp1];
tp1 = top[u];
}if (u == v) return ans;
if (dep[u] > dep[v]) swap(u, v);
ans = max(query(1,id[son[u]], id[v]), ans);
return ans;
}void clear(int n)
int main()
build(1,num,1);
char s[200];
while(~scanf("%s",&s) && s[0]!='d')
clear(n);
}return
0;}
樹鏈剖分詳解及模板
這幾天學習了一下樹鏈剖分,順便寫一下我的理解 早上看了一下別人的講解,雲裡霧裡,終於算是搞懂了 樹鏈剖分是解決在樹上進行插點問線,插線問點等一系列樹上的問題 假如現在給你一棵樹,然後沒兩條邊之間有一條權值,有一些操作,1 x y之間的最大權值是多少,2 改變x y之間的權值 那麼就要想想辦法了,我們...
樹鏈剖分 模板
class match node a n struct no no aa n 4 void init void addpage int x,int y void dfs int s,int faa,int h 根節點,父節點和深度的 if max 0 son s sign void dfs2 int...
模板 樹鏈剖分
define maxn 50010 define l u u 1 define r u u 1 1 寫在類裡面爆棧 int n,m,q int tim 時間戳 int num maxn 樹上每個節點的初始值 int siz maxn siz u 表示以u為根的子樹的節點數 int top maxn ...