預備知識:線段樹,DFS序html
DFS序
DFS序,字面意思,就是DFS到的順序node
咱們只須要在搜到節點的時候記錄一下就能夠了c++
好比這樣多是一個樹的DFS序git
那知道了DFS序又有什麼用呢數組
咱們能夠發現一顆子樹在DFS序上是連續的一段ide
那麼它就有了一個區間的性質,每一個節點對應一段區間,那麼咱們在進行一些操做像什麼:將以某節點爲根的子樹節點都加上x時,就能夠轉化爲在線段樹內的區間加了ui
樹鏈剖分
首先咱們要清楚一些概念:spa
重兒子(節點):子樹結點數目最多的結點.net
輕兒子(節點):除了重兒子之外的結點code
重邊:父親結點和重兒子連成的邊
輕邊:父親節點和輕兒子連成的邊
重鏈:由多條重邊鏈接而成的路徑
輕鏈:由多條輕邊鏈接而成的路徑
看圖感覺一下,
能夠看到:對於1節點4的子樹的節點比2,3的多,因此4是重兒子
對於4節點9的子樹的節點比8,9的多,因此9是重兒子
以此類推
因此結果是:圖中黑色的節點是重兒子,其他的節點是輕兒子
紅邊是重邊,黑邊是輕邊
1 - 4 - 9 - 13 - 14;3 - 7;2 - 6 - 11是重鏈
咱們發現:葉節點沒有重兒子,非葉節點有且只有1個重兒子
並非輕兒子以後全是輕兒子,好比3後面就有6和11兩個重兒子
咱們就能夠這樣理解:
當一個節點選了他的重兒子以後,咱們並不能保證它的輕兒子就是葉節點,因此咱們就以這個輕兒子爲根,再去選這個輕兒子的輕重兒子
也就是一個DFS的過程,這樣咱們就會獲得不少重鏈
有以下兩個性質:
1.輕邊(u,v)中, size(u)≤ size(u/2)
2.從根到某一點的路徑上,不超過logn條輕鏈和不超過logn條重鏈。
那咱們要怎麼求出輕重兒子呢
這裏咱們定義幾個數組:
son[u]:表示u的重兒子
size[u]:表示以u爲根的樹的節點個數,如上圖的size[1] = 13
在這裏,咱們還能夠順帶的求出
f[u]:節點的父節點
dep[u]:節點的深度
//u是當前節點 //fa是當前節點的父節點 void dfs1(int u, int fa) { size[u] = 1;//表示剛搜到u的時候以u爲根的子樹裏只有u一個節點 for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v;//連向的節點 if (v != fa) {//由於連的是無相邊,並且是樹,不能往上搜,因此咱們要判斷u是否是從fa搜過來,也就是判斷v是否是u的子節點,也能夠寫做!dep[v](沒有被搜到過) dep[v] = dep[u] + 1;//v的深度是當前節點的深度+1 f[v] = u;//記錄一下父親 dfs1(v, u);//繼續往下搜,一直搜到葉節點爲止 size[u] += size[v];//往上回溯,更新以u爲根的子樹的size if (size[v] > size[son[u]]) son[u] = v;//重兒子是節點個數更多的子樹,若是以u的子樹中,以v爲根的子樹節點多,那就更新一下u的重兒子爲v } } }
這樣咱們就求出了這棵樹的全部重兒子,全部點的深度,和全部點的父親。
既然咱們已經求出來重兒子,輕兒子那麼咱們就要把他們連成鏈
由於咱們要把輕重兒子連城鏈,因此咱們就必定要讓鏈上的點連續,方便咱們的操做
那該怎麼辦呢,這就用到了咱們以前提到的DFS序了
咱們從根開始一遍DFS,若是有重兒子就先走重兒子(將一條重鏈放到一個區間內),搜到葉子節點後回溯回去再去搜輕兒子(輕鏈)
這一遍DFS裏,咱們又引入了幾個數組:
top[u]:節點u所在鏈的頂端
id[u]:節點u的新編號(DFS序)
a[cnt]:在新編號(DFS序)下的當前點的點值
w[u]:題目中給出的節點u的點值
//u是當前節點 //t是所在鏈的頂端 void dfs2(int u, int t) { id[u] = ++cnt;//給這個點一個新的編號 a[cnt] = w[u];//記錄這個編號下點的值 top[u] = t;//記錄u所在鏈的頂端爲t if (son[u]) dfs2(son[u], t);//u的重兒子和u在同一條鏈裏 for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v;//搜輕兒子 if (v != f[u] && v != son[u])//判斷是不是輕兒子 dfs2(v, v);//以輕兒子爲頂的鏈 } }
爲何是dfs2(v,v)呢,由於當v是重兒子的時候,它不可能爲一條鏈的頂,由於根據重邊的定義,必定有一條邊連向重兒子,若重兒子爲頂,還會有一條邊連向它,因此重兒子不會爲頂端。
樹鏈剖分求LCA
爲何要先講樹剖求LCA呢
由於樹剖的不少題是要求要在鏈上進行操做的,而鏈上操做其實就是LCA
樹剖求LCA其實也是往上跳,但這裏的往上跳不是倍增的往上跳
咱們這裏只要把兩個點跳到同一條鏈裏就行了
如圖:咱們要求LCA的話,有兩種狀況
一、在同一條鏈內,如3和5。這時直接輸出深度較小的那個節點就行了
二、再也不同一條鏈內,如6和8。由於他們再也不一條鏈內,因此咱們讓其中一個點 x 直接跳到鏈的頂端也是沒有問題的。這時咱們就讓那個深度深的 x 一直往上跳,這把 x 更新 x 的頂端的父親節點,也就是到了另外一條鏈上,記錄一下它在這條新鏈上的頂端是誰,用來判斷和另外一個點 y 是否在同一條鏈內。當 x 跳到它所在的鏈的頂端時,深度可能就小於 y 的頂端了,也就是在另外一條鏈的上面(這時 x 不會再往上跳,y 也不會再往上跳,但沒有找到LCA),這時咱們就要交換他們(其實只是換了個名字,管原來的 y 叫 x ,管原來的 x 叫 y,原來的樹並無變,想了好久),保證 x , y 會更新到同一條鏈內
稍微模擬一下
如圖:
若是咱們要求6和12的LCA
設x = 12,y = 1
這時咱們先比較一下二者的top,fx = top[x] = 12,fy = top[y] = 1
發現他們的top不同
那就往上跳唄,dep[fx] > dep[fy],因此 x = f[fx] = 9,fx = top[x] = 7
12往上跳跳到了9
變成了這樣
找到9所在鏈的頂爲7
發現7 != 1說明9和1再也不同一個鏈裏
繼續往上跳
x = top[fx] = 2,fx = top[2] = 1
發現1 == 1
說明咱們如今的 x 和 y 在同一條鏈裏了
這時咱們就返回深度小的那個就能夠了
//fx表示x所在鏈的頂,fy表示y所在鏈的頂 int LCA(int x, int y) { int fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); x = f[fx], fx = top[x]; } return dep[x] < dep[y] ? x : y;//最後返回深度小的那個 }
若是還有邊權的話,只要在dfs1里加1句話就能夠了
void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; dis[v] = dis[u] + e[i].w;//here dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } }
dis[u]表示從根到u的距離,其實倍增,tarjan都是這麼着
查詢距離的時候仍是
dis[x] + dis[y] - 2 * dis[LCA(x, y)]
路徑上的修改/查詢
講完了LCA,剩下的路徑上修改和查詢就和LCA差很少了,只是加了幾句話而已
這裏要結合咱們上面的DFS序和LCA
那對於路徑上的操做,咱們先想LCA,在求LCA的時候,咱們每次都往上跳一條鏈,直到這兩個點在一個路徑上爲止
就像咱們剛開始的找6的top同樣
一次就通過了這麼一條鏈(綠邊)
咱們再回想一下DFS序的性質,會獲得在這一條鏈上,新的編號是連續的,咱們要對這一條鏈進行修改和查詢操做,這讓咱們想到了什麼
線段樹!!
線段樹最支持的不就是區間修改和查詢嗎
那麼咱們就能夠用線段樹維護這一條路徑了。
那若是咱們要維護6到12這樣一條路徑呢?
還記得咱們求LCA的時候是怎麼往上跳的嗎
左半部分的12往上跳,每次都跳到所在鏈的頂端(只記錄初末位置),咱們能夠獲得12跳到的當前點 u 所處的鏈的頂的新編號(跳到9,頂爲7),咱們又知道當前點 u 的新編號,那咱們就能夠用線段樹對從頂段到當前點 u 這條路徑進行操做了,這樣咱們每次修改一條鏈(多是一部分),就完成了路徑的操做;
跳到2的時候,fx == fy,兩點在同一條鏈內,x = 2,y = 6,而後咱們操做 id[2] 到 id[6] ,這樣咱們就一條鏈一條鏈的完成了對這條路徑的操做
全程咱們操做的區間是[id[2],id[6]],[id[7],id[9]],[id[12],id[12]]
咱們不對藍邊上的點和綠邊上的點操做,由於他們不是重鏈,只是註明一下點通過的路徑,若對它們操做的話會算重複
我剛寫完這句話的時候想到了一個error
若是圖長這樣
(虛線是我省略了那一串的點)
若是咱們要查詢 103 到 101 呢,它們之間沒有重鏈啊,那隻好就一個一個的往上跳了,103->102->101.(退化成單點操做)
//修改 void update_chain(int x, int y, int z) { int fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); update(id[fx], id[x], z, 1, cnt, 1);//每往上跳一次,就修改以次通過路徑上的值,由於DFS序中id[fx] < id[x],因此是區間[id[fx],id[x]]; x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y);//要保證區間是從小到大的 update(id[x], id[y], z, 1, cnt, 1); }
//查詢 int query_chain(int x, int y) { int ans = 0, fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans += query(id[fx], id[x], 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans += query(id[x], id[y], 1, cnt, 1); return ans; }
到此爲止,咱們就完成了樹鏈剖分的基本操做
完整代碼:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int n, m, num, cnt, rt, cntt, k, s, mod; int head[N], size[N], top[N], f[N], son[N], dep[N], a[N], id[N], w[N]; struct node { int v, nx; } e[N]; struct tree { int sum, lazy; int len; } t[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T>inline void read(T &x) { x = 0; int f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); x = f ? -x : x; return ; } inline void add(int u, int v) { e[++num].nx = head[u], e[num].v = v, head[u] = num; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++ cnt; a[cnt] = w[u]; top[u] = t; if (son[u]) dfs2(son[u], t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } inline void pushup(int rt) { t[rt].sum = t[lson].sum + t[rson].sum; } void build(int l, int r, int rt) { t[rt].len = r - l + 1; if (l == r) { t[rt].sum = a[l]; return; } int m = (l + r) >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(rt); } inline void pushdown(int rt) { if (t[rt].lazy) { t[lson].lazy += t[rt].lazy, t[lson].lazy %= mod; t[rson].lazy += t[rt].lazy, t[rson].lazy %= mod; t[lson].sum += t[rt].lazy * t[lson].len, t[lson].sum %= mod; t[rson].sum += t[rt].lazy * t[rson].len, t[rson].sum %= mod; t[rt].lazy = 0; } } void update(int L, int R, int c, int l, int r, int rt) { if (L <= l && r <= R) { t[rt].sum += (t[rt].len * c) % mod; t[rt].lazy += c; return ; } pushdown(rt); int m = (l + r) >> 1; if (L <= m) update(L, R, c, l, m, lson); if (R > m) update(L, R, c, m + 1, r, rson); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return t[rt].sum; pushdown(rt); int m = (l + r) >> 1, ans = 0; if (L <= m) ans += query(L, R, l, m, lson) % mod; if (R > m) ans += query(L, R, m + 1, r, rson) % mod; return ans % mod; } void update_chain(int x, int y, int z) { int fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); update(id[fx], id[x], z, 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); update(id[x], id[y], z, 1, cnt, 1); } int query_chain(int x, int y) { int ans = 0, fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans += query(id[fx], id[x], 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans += query(id[x], id[y], 1, cnt, 1); return ans % mod; } int main(int argc, char const *argv[]) { memset(head, -1, sizeof(head)); read(n), read(m), read(s), read(mod); for (int i = 1; i <= n; ++ i) read(w[i]); for (int i = 1, x, y; i < n; ++ i) { read(x), read(y); add(x, y), add(y, x); } f[s] = 1, dep[s] = 0; dfs1(s, 0); dfs2(s, s); build(1, n, 1); for (int i = 1, x, y, z; i <= m; ++i) { read(k), read(x); if (k == 1) {read(y), read(z); update_chain(x, y, z);} if (k == 2) {read(y); printf("%d\n", query_chain(x, y));} if (k == 3) {read(z); update(id[x], id[x] + size[x] - 1, z, 1, n, 1);} if (k == 4) printf("%d\n", query(id[x], id[x] + size[x] - 1, 1, n, 1) % mod); } return 0; }
例題:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 5e6 + 10; int n, m, num, cnt, cntt, rt; int head[N], dep[N], f[N], id[N], size[N], w[N], son[N], a[N], top[N]; struct node { int v, nx; } e[N]; struct tree { ll sum, lazy; int len; } t[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T>inline void read(T &x) { x = 0; int f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); x = f ? -x : x; return; } inline void add(int u, int v) { e[++num].nx = head[u], e[num].v = v, head[u] = num; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++ cnt; a[cnt] = w[u]; top[u] = t; if (son[u]) dfs2(son[u], t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } inline void pushup(int rt) { t[rt].sum = t[lson].sum + t[rson].sum; } void build(int l, int r, int rt) { t[rt].len = r - l + 1; if (l == r) { t[rt].sum = a[l]; return; } int m = l + r >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(rt); } inline void pushdown(int rt) { if (t[rt].lazy) { t[lson].lazy += t[rt].lazy; t[rson].lazy += t[rt].lazy; t[lson].sum += t[rt].lazy * t[lson].len; t[rson].sum += t[rt].lazy * t[rson].len; t[rt].lazy = 0; } } void update(int L, int R, ll c, int l, int r, int rt) { if (L <= l && r <= R) { t[rt].sum += c * t[rt].len; t[rt].lazy += c; return ; } int m = l + r >> 1; pushdown(rt); if (L <= m) update(L, R, c, l, m, lson); if (R > m) update(L, R, c, m + 1, r, rson); pushup(rt); } ll query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return t[rt].sum; pushdown(rt); int m = l + r >> 1; ll ans = 0; if (L <= m) ans += query(L, R, l, m, lson); if (R > m) ans += query(L, R, m + 1, r, rson); return ans; } ll query_chain(int x, int y) { ll ans = 0; int fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans += query(id[fx], id[x], 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans += query(id[x], id[y], 1, cnt, 1); return ans; } int main(int argc, char const *argv[]) { memset(head, -1, sizeof(head)); read(n), read(m); for (int i = 1; i <= n; ++ i) read(w[i]); for (int i = 1, x, y; i < n; ++ i) { read(x), read(y); add(x, y), add(y, x); } dep[1] = 1; dfs1(1, 0), dfs2(1, 1); build(1, n, 1); for (int i = 1, x, y, z; i <= m; ++ i) { read(x), read(y); if (x == 1) read(z), update(id[y], id[y], z, 1, n, 1); if (x == 2) read(z), update(id[y], id[y] + size[y] - 1, z, 1, n, 1); if (x == 3) printf("%lld\n",query_chain(1,y)); } return 0; }
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, m, num, cnt, cntt, rt; int head[N], size[N], dep[N], f[N], id[N], w[N], a[N], top[N], son[N]; string s; struct node { int v, nx; } e[N]; struct tree { int sum, lazy, mx; int len; } t[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T> inline void read(T &x) { x = 0; int f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); x = f ? -x : x; return; } inline void add(int u, int v) { e[++num].nx = head[u], e[num].v = v, head[u] = num; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { f[v] = u; dep[v] = dep[u] + 1; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++ cnt; a[cnt] = w[u]; top[u] = t; if (son[u]) dfs2(son[u],t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } inline void pushup(int rt) { t[rt].sum = t[lson].sum + t[rson].sum; t[rt].mx = max(t[lson].mx, t[rson].mx); } void build(int l, int r, int rt) { t[rt].len = r - l + 1; if (l == r) { t[rt].sum = t[rt].mx = a[l]; return; } int m = l + r >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(rt); } void update(int L, int c, int l, int r, int rt) { if (l == r) { t[rt].sum = c; t[rt].mx = c; return; } int m = l + r >> 1; if (L <= m) update(L, c, l, m, lson); else update(L, c, m + 1, r, rson); pushup(rt); } int query_sum(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return t[rt].sum; int m = l + r >> 1, ans = 0; if (L <= m) ans += query_sum(L, R, l, m, lson); if (R > m) ans += query_sum(L, R, m + 1, r, rson); return ans; } int query_max(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return t[rt].mx; int m = l + r >> 1, ans = -0x3f3f3f3f; if (L <= m) ans = max(ans, query_max(L, R, l, m, lson)); if (R > m) ans = max(ans, query_max(L, R, m + 1, r, rson)); return ans; } int query_chain_sum(int x, int y) { int ans = 0, fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans += query_sum(id[fx], id[x], 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans += query_sum(id[x], id[y], 1, cnt, 1); return ans; } int query_chain_max(int x, int y) { int ans = -0x3f3f3f3f, fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans = max(ans, query_max(id[fx], id[x], 1, cnt, 1)); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans = max(ans, query_max(id[x], id[y], 1, cnt, 1)); return ans; } int main(int argc, char const *argv[]) { memset(head, -1, sizeof(head)); read(n); for (int i = 1, x, y; i < n; ++ i) { read(x), read(y); add(x, y), add(y, x); } for (int i = 1; i <= n; ++ i) read(w[i]); f[1] = 0, dep[1] = 1; dfs1(1, 0), dfs2(1, 1); build(1, n, 1); read(m); for (int i = 1, x, y; i <= m; ++ i) { cin >> s; if (s == "CHANGE") read(x), read(y), update(id[x], y, 1, n, 1); if (s == "QMAX") read(x), read(y), printf("%d\n", query_chain_max(x, y)); if (s == "QSUM") read(x), read(y), printf("%d\n", query_chain_sum(x, y)); } return 0; }
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
//路徑最值 #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int n, m, num, cnt; int head[N], f[N], top[N], son[N], size[N], dep[N], id[N]; struct node { int v, nx; } e[N]; struct tree { int mx; int lazy; } t[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T>inline void read(T &x) { x = 0; int f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); x = f ? -x : x; return; } inline void add(int u, int v) { e[++num].nx = head[u], e[num].v = v, head[u] = num; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++cnt; top[u] = t; if (son[u]) dfs2(son[u], t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } inline void pushup(int rt) { t[rt].mx = max(t[lson].mx, t[rson].mx); } void build(int l, int r, int rt) { if (l == r) return ; int m = (l + r) >> 1; build(l, m, lson); build(m + 1, r, rson); } void pushdown(int rt) { if (t[rt].lazy) { t[lson].lazy += t[rt].lazy; t[rson].lazy += t[rt].lazy; t[lson].mx += t[rt].lazy; t[rson].mx += t[rt].lazy; t[rt].lazy = 0; } } void update(int L, int R, int c, int l, int r, int rt) { if (L <= l && r <= R) { t[rt].lazy += c; t[rt].mx += c; return; } int m = (l + r) >> 1; pushdown(rt); if (L <= m) update(L, R, c, l, m, lson); if (R > m) update(L, R, c, m + 1, r, rson); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return t[rt].mx; int m = (l + r) >> 1, ans = -0x3f3f3f3f; if (L <= m) ans = max(ans, query(L, R, l, m, lson)); if (R > m) ans = max(ans, query(L, R, m + 1, r, rson)); return ans; } void update_chain(int x, int y) { int fx = top[x], fy = top[y]; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); update(id[fx], id[x], 1, 1, cnt, 1); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); update(id[x], id[y], 1, 1, cnt, 1); } int main(int argc, char const *argv[]) { memset(head, -1, sizeof(head)); read(n), read(m); for (int i = 1, x, y; i < n; ++i) { read(x), read(y); add(x, y), add(y, x); } f[1] = 0, dep[1] = 1; dfs1(1, 0), dfs2(1, 1); build(1, n, 1); for (int i = 1, x, y; i <= m; ++i) { read(x), read(y); if (x > y) swap(x, y); update_chain(x, y); } printf("%d\n", query(id[1], id[1] + size[1] - 1, 1, n, 1)); return 0; }
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
//樹鏈剖分,可是要轉換一下,把邊權轉化爲所連向點的點權,查詢的時候要忽略最上面的點 #include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int n, num, cnt, x, y, z; int dep[N], f[N], top[N], size[N], son[N], a[N], w[N], head[N], mx[N], id[N]; struct node { int v, nx, w; } e[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T>inline void read(T &x) { x = 0; int f = 0; char ch = getchar(); while (!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); x = f ? -x : x; return ; } inline void add(int u, int v, int w) { e[++num].nx = head[u], e[num].v = v, e[num].w = w, head[u] = num; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; w[v] = e[i].w; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++cnt; a[cnt] = w[u]; top[u] = t; if (son[u]) dfs2(son[u], t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } inline void pushup(int rt) { mx[rt] = max(mx[lson], mx[rson]); } void build(int l, int r, int rt) { if (l == r) { mx[rt] = a[l]; return ; } int m = (l + r) >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(rt); } void update(int L, int c, int l, int r, int rt) { if (l == r) { mx[rt] = c; return ; } int m = (l + r) >> 1; if (L <= m) update(L, c, l, m, lson); else update(L, c, m + 1, r, rson); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return mx[rt]; int m = (l + r) >> 1, ans = -0x3f3f3f3f; if (L <= m) ans = max(ans, query(L, R, l, m, lson)); if (R > m) ans = max(ans, query(L, R, m + 1, r, rson)); return ans; } int query_chain(int x, int y) { int fx = top[x], fy = top[y], ans = -0x3f3f3f3f; while (fx != fy) { if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy); ans = max(ans, query(id[fx], id[x], 1, cnt, 1)); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans = max(ans, query(id[x] + 1, id[y], 1, cnt, 1)); return ans; } int main(int argc, char const *argv[]) { memset(head, -1, sizeof(head)); read(n); for (int i = 1; i < n; ++i) { read(x), read(y), read(z); add(x, y, z), add(y, x, z); } f[1] = 0, dep[1] = 1; dfs1(1, 0), dfs2(1, 1); build(1,n,1); while (1) { string s; cin >> s; if (s == "QUERY") { read(x), read(y); if (x == y) printf("0\n"); else printf("%d\n", query_chain(x, y)); } else if (s == "CHANGE") { read(x), read(y); x = (x << 1) - 1; update(id[e[x].v],y,1,n,1); } else break; } return 0; }
P3038 [USACO11DEC]牧草種植Grass Planting
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
#include <bits/stdc++.h> using namespace std; const int N = 4e5 + 10; int n,m,cnt,num; int top[N],f[N],son[N],size[N],id[N],head[N],dep[N]; struct node { int v,nx; }e[N]; struct tree { int sum; int lazy; }t[N]; #define lson rt << 1 #define rson rt << 1 | 1 template<class T>inline void read(T &x) { x = 0;int f = 0;char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'),ch = getchar(); while(isdigit(ch)) x = x * 10 + ch - '0',ch = getchar(); x = f ? -x : x; return; } inline void add(int u,int v) { e[++num].nx = head[u],e[num].v = v,head[u] = num; } void dfs1(int u,int fa) { size[u] = 1; for(int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if(v != fa) { dep[v] = dep[u] + 1; f[v] = u; dfs1(v,u); size[u] += size[v]; if(size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u,int t) { top[u] = t; id[u] = ++cnt; if(son[u]) dfs2(son[u],t); for(int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if(v != f[u] && v != son[u]) dfs2(v,v); } } inline void pushup(int rt) { t[rt].sum = t[lson].sum + t[rson].sum; } inline void pushdown(int l,int r,int rt) { if(t[rt].lazy) { t[lson].lazy += t[rt].lazy; t[rson].lazy += t[rt].lazy; t[lson].sum += t[rt].lazy * l; t[rson].sum += t[rt].lazy * r; t[rt].lazy = 0; } } void update(int L,int R,int l,int r,int rt) { if(L <= l && r <= R) { t[rt].sum += (r - l + 1); t[rt].lazy += 1; return ; } int m = (l + r) >> 1; pushdown(m - l + 1,r - m,rt); if(L <= m) update(L,R,l,m,lson); if(R > m) update(L,R,m + 1,r,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L <= l && r <= R) return t[rt].sum; int m = (l + r) >> 1,ans = 0; pushdown(m - l + 1,r - m,rt); if(L <= m) ans += query(L,R,l,m,lson); if(R > m) ans += query(L,R,m + 1,r,rson); return ans; } void update_chain(int x,int y) { int fx = top[x],fy = top[y]; while(fx != fy) { if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy); update(id[fx],id[x],1,cnt,1); x = f[fx],fx = top[x]; } if(id[x] > id[y]) swap(x,y); update(id[x] + 1,id[y],1,cnt,1); } int query_chain(int x,int y) { int fx = top[x],fy = top[y],ans = 0; while(fx != fy) { if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy); ans += query(id[fx],id[x],1,cnt,1); x = f[fx],fx = top[x]; } if(id[x] > id[y]) swap(x,y); ans += query(id[x] + 1,id[y],1,cnt,1); return ans; } int main(int argc, char const *argv[]) { memset(head,-1,sizeof(head)); read(n),read(m); for(int i = 1,x,y; i < n; ++i) { read(x),read(y); add(x,y),add(y,x); } f[1] = 0,dep[1] = 1; dfs1(1,0),dfs2(1,1); for(int i = 1,x,y; i <= m; ++ i) { char c; cin>>c; read(x),read(y); if(c == 'P') update_chain(x,y); else printf("%d\n", query_chain(x,y)); } return 0; }