您的位置:首页 > 其它

POJ 1741|BZOJ 1468|Tree|树分治

2016-03-23 22:55 471 查看
求树上距离不超过K的点对数。

一条链有2种情况:

经过根,两端点在子树中

这种就包含了经过根节点而且向父亲延伸的情况。

然后又有两种情况

两端点在根的一个子树中

不合法,因为这样距离不是最短

两端点在根的不同子树中

答案就是本情况的种类数。但似乎不好计算。

可以考虑直接统计2种情况的总方案数再减去情况1的方案数。

总方案数的求法很简单,统计根到子树中所有点的距离,然后按距离排序,枚举左端点,而右端点是单调不升,所以复杂度为O(nlogn)。

而统计情况1可以转化为求总情况(根到LCA间距只影响K)。

整个在子树中

递归处理转化为情况1

为了保证复杂度,需要实时求重心。

所谓树分治,就是确定某个点对答案的贡献度,一旦确定,这个点就可以扔了,毕竟我们不需要再统计它一次。而与某个点有关联的点的个数会随着分治层数的增加而减少,而每次至少减少一半,所以复杂度:

T(n)=xT(nx)+O(nlogn)=O(nlog2n)

其中x≥2。

#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 10005, M = 50005;
#define adj(i,j) for(int i=h[j];i;i=p[i])if(v[i]!=fa&&!vis[v[i]])
using namespace std;
int h
, p[M], w[M], v[M], cnt = 0;
int n, k, vis
, ans, rt, c;
void add(int a, int b, int c) {
v[++cnt] = b; w[cnt] = c; p[cnt] = h[a]; h[a] = cnt;
}
int mx
, sz
, mi, dis
;
void dfssize(int x, int fa) {
sz[x] = 1; mx[x] = 0;
adj(i,x) {
dfssize(v[i], x);
sz[x] += sz[v[i]];
if (sz[v[i]] > mx[x]) mx[x] = sz[v[i]];
}
}
void dfsrt(int r, int x, int fa) {
if (sz[r] - sz[x] > mx[x]) mx[x] = sz[r] - sz[x];
if (mx[x] < mi) mi = mx[x], rt = x;
adj(i,x) dfsrt(r, v[i], x);
}
void dfsdis(int x, int d, int fa) {
dis[c++] = d;
adj(i,x) dfsdis(v[i], d + w[i], x);
}
int calc(int x, int d) {
int ans = 0;
c = 0;
dfsdis(x, d, 0);
sort(dis, dis + c);
for (int i = 0, j = c - 1; i < j; ++i) {
for (; dis[i] + dis[j] > k && i < j; --j);
ans += j - i;
}
return ans;
}
void dfs(int x) {
int fa = 0;
mi = n;
dfssize(x, fa); dfsrt(x, x, fa);
ans += calc(rt, 0);
vis[rt] = 1;
adj(i, rt) {
ans -= calc(v[i], w[i]);
dfs(v[i]);
}
}
int main() {
int u, v, w, i;
while(scanf("%d%d", &n, &k) != EOF && (n || k)) {
memset(vis, 0, sizeof vis);
memset(h, 0, sizeof h);
cnt = ans = 0;
for (i = 1; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
dfs(1);
printf("%d\n", ans);
}
return 0;
}


Tree

Time Limit: 1000MS Memory Limit: 30000K

Total Submissions: 16116 Accepted: 5249

Description

Give a tree with n vertices,each edge has a length(positive integer less than 1001).

Define dist(u,v)=The min distance between node u and v.

Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.

Write a program that will count how many pairs which are valid for a given tree.

Input

The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l.

The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0


Sample Output

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