模板及講解
樹鏈剖分解決樹上的修改問題。
將樹剖成一條條鏈,再用線段樹、樹狀陣列等維護
常見題型:
1.點權問題
q:修改某些點的權進行詢問。
解:直接樹剖進行線段樹/樹狀陣列維護
例題:bzoj1036
2.邊權問題
q:修改某些邊的權進行詢問。
解:樹剖後維護點權,每個點的點權為這個點到他父親之間邊權,詢問時刪除lca的點權即可
例題:poj2763
3.子樹問題
#include
#include
#include
#include
#define fo(i, j, k) for (i=(j);i<=(k);i++)
#define fd(i, k, j) for (i=(k);i>=(j);i--)
#define rd(a) scanf("%d", &a)
#define rd2(a, b) scanf("%d%d", &a, &b)
#define rd3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define ms(i, j) memset(i, j, sizeof i)
#define fn2 "bzoj1036"
using
namespace
std;
const
int maxn = 30000 + 5;
int dep[maxn], son[maxn], fa[maxn], siz[maxn]; //深度,重兒子,父親,子樹大小
int n, wi[maxn];
vector
g[maxn];
void dfs1(int u, int f)//第一次dfs記錄值
}}int maxv[maxn*4], sumv[maxn*4];
void pushup(int o)
void update(int o, int l, int r, int p, int v)
if (p<=m) update(lc, l, m, p, v); else
if (m1, r, p, v);
pushup(o);
}int getmax(int o, int l, int r, int x, int y)
if (x<=m) ret = max(ret, getmax(lc, l, m, x, y));
if (m1, r, x, y));
return ret;
}int getsum(int o, int l, int r, int x, int y)
if (x<=m) ret += getsum(lc, l, m, x, y);
if (m1, r, x, y);
return ret;
}int findmax(int u, int v)
if (dep[u]return max(ret, getmax(1, 1, n, p[v], p[u]));
}int findsum(int u, int v)
if (dep[u]return ret+getsum(1, 1, n, p[v], p[u]);
}void init()
}void solve() else
if (ch[1]=='m') else
if (ch[1]=='s')
}}int main()
樹鏈剖分學習筆記
寫 又犯了很sb的錯誤,線段樹寫錯了。好像每次都會把r l 1寫成l r 1,然後就只有20分。寫的比較醜,壓了壓之後190行。基本上是我打過的最長的乙個模板了 然後簡單介紹一下樹剖吧。樹鏈剖分,就是把樹剖分成鏈,然後用資料結構來維護這些鏈,使得詢問 修改的複雜度達到o logn o l ogn 不...
樹鏈剖分學習筆記
樹鏈剖分 mod estc oder modestcoder modest code r如果你是重兒子,你就在重路徑上。如果你是輕兒子,暴力沿著祖先向上爬最多log nlogn logn 次就可以遇到重路徑。或者到根 而樹上操作基本就是找祖先 也許有人喜歡我的碼風 include include d...
樹鏈剖分學習筆記
前言 書上只講了重鏈剖分,菜雞也只會這一種,想看其他的是別想了。要會樹鏈剖分,首先你需要了解一些概念。我們把乙個節點的所有兒子節點中子樹節點數最大的稱為重兒子,也就是size最大的子節點。size的定義我在講換根dp時說過,因此不再贅述。對於每個節點的重兒子,我們用 son x 來記錄它,父親節點到...