POJ 1741 树的分治(点分治)入门

时间:2014-02-21 09:47:49   收藏:0   阅读:370

看一下09年漆子超的论文,是论文的第一题,思路在其中讲得很清楚了。

复杂度分析:每次先找当前树的重心,再从重心为根遍历这颗树, 从表面上看来这个复杂度很大,但事实并非如此,通过找多次重心,使整棵树的深度不超过log(n), 所以对于每个点的访问次数不超过log(n), 总体复杂度nlog(n), 如果在dfs里面添加一些操作,那么就要把复杂度乘上去,这题cal的复杂度是log(n), 总体复杂度nlog^2(n)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10005;
struct Edge {
	int v, w, next;
} g[maxn << 2];
int head[maxn], E;
int n, k;
void init() {
	memset(head, -1, sizeof(head));
	E = 0;
	ans = 0;
	memset(vis, false, sizeof(vis));
}
void add(int s, int t, int w) {
	g[E].v = t;
	g[E].w = w;
	g[E].next = head[s];
	head[s] = E++;
}

int sz[maxn], mx[maxn];
bool vis[maxn];
void dfsSz(int u, int fa) { //计算子树大小
	mx[u] = 0, sz[u] = 1;
	for(int i = head[u]; ~i; i = g[i].next) {
		int v = g[i].v;
		if(v == fa || vis[v]) continue;
		dfsSz(v, u);
		sz[u] += sz[v];
		mx[u] = max(mx[u], sz[v]);
	}
}
int root, mi;
void dfsRt(int rt, int u, int fa) { //计算重心,并用root保存
	mx[u] = max(mx[u], sz[rt] - sz[u]);
	if(mi > mx[u]) mi = mx[u], root = u;
	for(int i = head[u]; ~i; i = g[i].next) {
		int v = g[i].v;
		if(v == fa || vis[v]) continue;
		dfsRt(rt, v, u);
	}
}
int dis[maxn], num;
void dfsDis(int u, int fa, int d) { //把子树的dis放入数组中
	dis[num++] = d;
	for(int i = head[u]; ~i; i = g[i].next) {
		int v = g[i].v;
		if(v == fa || vis[v]) continue;
		dfsDis(v, u, d + g[i].w);
	}
}
int cal(int u, int d) { //计算答案
	num = 0;
	dfsDis(u, -1, d);
	sort(dis, dis + num);
	int i = 0, j = num - 1, ret = 0;
	while (i < j) {
		while (i < j && dis[i] + dis[j] > k)
			j--;
		ret += j - i;
		i++;
	}
	return ret;
}
int ans;
void dfs(int u) {
	mi = n;
	dfsSz(u, -1);
	dfsRt(u, u, -1);
	ans += cal(root, 0);
	vis[root] = 1;
	for(int i = head[root]; ~i; i = g[i].next) {
		int v = g[i].v;
		if(vis[v]) continue;
		ans -= cal(v, g[i].w);
		dfs(v);
	}
}
int main() {
	while (~scanf("%d%d", &n, &k)) {
		if(!n && !k) break;
		init();
		int x, y, z;
		for(int i = 1; i < n; i++) {
			scanf("%d%d%d", &x, &y, &z);
			add(x, y, z);
			add(y, x, z);
		}
		dfs(1);
		printf("%d\n", ans);
	}
	return 0;
}


原文:http://blog.csdn.net/auto_ac/article/details/19567291

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!