帶權無根樹上簡單路徑統計問題的算法
將樹上問題轉化爲子問題求解,每次統計字節點貢獻求和便可node
Luogu P4178 Tree
題目大意,給一棵樹一個\(k\),求距離小於等於\(k\)的點對數量ios
\(LCA\)板子直接\(T30\)沒啥說的算法
對於一棵無根樹,找到一個點,使得知足若是以它爲根,它的最大子樹大小盡可能小,這個點稱爲重心。
好比這條鏈狀結構,若是選取1爲根節點,遞歸時間複雜度飆升至\(O(N^2)\),若是選取重心3做爲根節點那麼時間複雜度維持在\(O(nlog_n)\)數組
在處理樹上兩個點的時候,兩點的位置關係一共有三種ide
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; inline int read(){ int x = 0, w = 1; char ch = getchar(); for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return x * w; } const int ss = 1000010; struct node{ int to, nxt, w; }edge[ss << 1]; int head[ss << 1], tot; inline void add(int u, int v, int w){ edge[++tot].to = v; edge[tot].nxt = head[u]; edge[tot].w = w; head[u] = tot; } int size[ss], sz, maxx[ss], root; bool vis[ss]; inline void getroot(register int u,register int f){ size[u] = 1; maxx[u] = 0; for(register int i = head[u]; i; i = edge[i].nxt){ register int v = edge[i].to; if(v == f || vis[v]) continue; getroot(v, u); size[u] += size[v]; maxx[u] = max(maxx[u], size[v]); } maxx[u] = max(maxx[u], sz - size[u]); maxx[u] = maxx[u]; if(maxx[u] < maxx[root]) root = u; } int a[ss], cnt; inline void getdis(int u, int f, int d){ a[++cnt] = d; for(int i = head[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == f || vis[v]) continue; getdis(v, u, d + edge[i].w); } } int n, k; inline int calc(int u, int d){ int sum = 0; cnt = 0; getdis(u, 0, d); sort(a + 1, a + 1 + cnt); int r = cnt; for(int l = 1; l <= cnt; l++){ while(r && a[l] + a[r] > k) r--; if(l > r) break; sum += r - l + 1; } return sum; } int ans; inline void divide(int u){ ans += calc(u, 0); vis[u] = 1; for(int i = head[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v]) continue; ans -= calc(v, edge[i].w); root = 0; sz = size[v]; getroot(v, u); divide(v); } } signed main(){ n = read(); for(int i = 1; i <= n - 1; i++){ int u = read(), v = read(), w = read(); add(u, v, w); add(v, u, w); } k = read(); maxx[0] = 0x7fffffff; getroot(1, 0); divide(root); cout << ans - n << endl; return 0; }
掌握分治思想&容斥操做spa