POJ-1741 Tree
题面
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
题意
求路径长度不超过k的路径数
题解
点分治(淀粉质)入门题
通过这篇文章已经简单对点分治入门了(https://blog.csdn.net/qq_39553725/article/details/77542223),知道了为什么要减去子树的答案,以及参数w的使用,这个题就是点分治的模板题了
首先我们对于这种统计树上路径数量,能否找到一条路径的题,可以考虑点分治,因为儿子的信息可能对父亲结点没什么用,对于那种需要维护子节点的信息合并到父节点,需要用儿子的信息算出父节点的答案的题,我们可以用启发式合并或者是dsu on tree
像这个题,直接套用点分治的板子,统计答案的时候先排序再two pointer扫一遍即可。
代码
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
struct node {
int v; ll w;
node() {}
node(int v, ll w): v(v), w(w) {}
};
const int N = 1e5 + 50;
const int inf = 1e9;
vector<node> G[N];
int sze[N];
int msze[N];
int S;
int maxx;
int vis[N];
int root;
void getroot(int u, int f) {
sze[u] = 1;
msze[u] = 0;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (vis[v] || v == f) continue;
getroot(v, u);
sze[u] += sze[v];
msze[u] = max(msze[u], sze[v]);
}
msze[u] = max(msze[u], S - sze[u]);
if (msze[u] < maxx) {
maxx = msze[u];
root = u;
}
}
ll dis[N];
int cnt = 0;
ll k;
void getdis(int u, int f, ll d) {
dis[++cnt] = d;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (vis[v] || v == f) continue;
getdis(v, u, d + G[u][i].w);
}
}
ll calc(int u, ll w) {
cnt = 0;
getdis(u, 0, w);
sort(dis + 1, dis + cnt + 1);
int l = 1, r = cnt;
ll ans = 0;
while (l <= r) {
if (dis[l] + dis[r] <= k) {
ans += r - l;
l++;
}
else r--;
}
return ans;
}
ll ans;
void dfs(int u) {
ans += calc(u, 0);
vis[u] = 1;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (vis[v]) continue;
ans -= calc(v, G[u][i].w);
S = sze[v];
root = 0;
maxx = inf;
getroot(v, 0);
dfs(root);
}
}
int main() {
int n;
while (scanf("%d%lld", &n, &k)) {
if (n == 0 && k == 0) break;
for (int i = 1; i <= n; i++) G[i].clear();
for (int i = 1; i < n; i++) {
int u, v; ll w;
scanf("%d%d%lld", &u, &v, &w);
G[u].push_back(node(v, w));
G[v].push_back(node(u, w));
}
memset(vis, 0, sizeof(vis));
cnt = 0;
S = n;
root = 0;
maxx = inf;
ans = 0;
getroot(1, 0);
dfs(root);
printf("%lld\n", ans);
}
return 0;
}
多组数据注意要清空的有:
- vis数组
- 答案ans
- 树的vector