带权无根树上简单路径统计问题的算法
将树上问题转化为子问题求解,每次统计字节点贡献求和便可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