给出N(1 <= N <= 200000)个结点的树,求长度等于K(1 <= K <= 1000000)的路径的最小边数。
点分治,这道题目和POJ 2114很接近,2114是求是否存在长度为K的边,但是那个K比较大。但是这道题目的K比之小了10倍。
1. 用V[i]表示到当前树根root的路径长度为i 时的点(赋值为root结点即可),这样就可以用来判断两条到根的路径长度之和是否等于K:
结点a的root的距离为i,结点b到root的距离为j,处理完a之后会得到V[i] = root,那么在处理结点b的时候,如果V[K-j] = root,就说明某一个a和b的路径长度为K,此时,就可以更新最小边数了。
2. e[i]表示到当前树根root的路径长度为i 时的边的最小条数。
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <iostream> using namespace std; #define N 200010 #define inf 0x3f3f3f3f struct node { int v, l; node() {} node(int _v, int _l): v(_v), l(_l) {}; }; vector<node> g[N]; int n, K, cur, root, size, ans; int s[N], f[N], d[N], e[N]; //s子树的结点数,f求重心,d子结点到根的距离,e子结点到根的边数 int v[N*10], c[N*10]; bool done[N]; void getroot(int now, int fa) { int u; s[now] = 1, f[now] = 0; for (int i=0; i<g[now].size(); i++) if ((u = g[now][i].v) != fa && !done[u]) { getroot(u, now); s[now] += s[u]; f[now] = max(f[now], s[u]); } f[now] = max(f[now], size-s[now]); if (f[now] < f[root]) root = now; } void dfs1(int now, int fa) { if (d[now] > K) return ; if (v[K-d[now]] == cur) ans = min(ans, c[K-d[now]]+e[now]); int u; for (int i=0; i<g[now].size(); i++) if ((u = g[now][i].v) != fa && !done[u]) { d[u] = d[now] + g[now][i].l; e[u] = e[now] + 1; dfs1(u, now); } } void dfs2(int now, int fa) { if (d[now] > K) return ; if (v[d[now]] != cur) { c[d[now]] = e[now]; v[d[now]] = cur; } else c[d[now]] = min(c[d[now]], e[now]); int u; for (int i=0; i<g[now].size(); i++) if ((u = g[now][i].v) != fa && !done[u]) dfs2(u, now); } void work(int now) { v[0] = cur = now + 1; int u; for (int i=0; i<g[now].size(); i++) if (!done[u = g[now][i].v]) { d[u] = g[now][i].l; e[u] = 1; dfs1(u, now); dfs2(u, now); } getroot(now, n); //更新s数组 done[now] = true; for (int i=0; i<g[now].size(); i++) if (!done[u = g[now][i].v]) { f[n] = size = s[u]; getroot(u, root=n); work(root); } } int main() { scanf("%d%d", &n, &K); for (int i=0; i<=n; i++) g[i].clear(); for (int i=1, a, b, c; i<n; i++) { scanf("%d%d%d", &a, &b, &c); g[a].push_back(node(b, c)); g[b].push_back(node(a, c)); } memset(done, false, sizeof(done)); ans = f[n] = size = n; getroot(0, root=n); work(root); printf("%d ", ans < n ? ans : -1); return 0; }