您的位置:首页 > 其它

BZOJ 2599 [IOI2011]Race【Tree,点分治】

2013-08-16 18:47 357 查看
给出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
;
int n, K, cur, root, size, ans;
int s
, f
, d
, e
;  //s子树的结点数,f求重心,d子结点到根的距离,e子结点到根的边数
int v[N*10], c[N*10];
bool done
;

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
= 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
= size = n;
getroot(0, root=n);
work(root);

printf("%d\n", ans < n ? ans : -1);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: