题意:给出一棵树,求两点路径之和小于等于k的点对数目。
思路:简单的树的点分治,每次找出树的重心,然后分两步求得ans,1,经过重心的路径。2,不经过重心的路径。
第二种情况,直接递归它的孩子的子树求的即可。对于第一种情况,我们一次遍历它的孩子子树,记录能形成距离,然后对于下一个孩子子树遍历时得到的距离,通过二分之前子树的距离,就可以得到有多少对点满足条件。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 40009
typedef long long ll;
struct E{
int v, d, ne;
E(){}
E(int _v, int _d, int _ne):v(_v), d(_d), ne(_ne){}
}e[N*2];
int n, m, size, ca = 1, head[N];
int vis[N] = {0}, sun[N], root, mi;
ll ans, k;
vector<ll>V[N];
inline void init() {
size = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int d) {
e[size] = E(v, d, head[u]);
head[u] = size++;
}
void cal(int u, int f, int s) {
int i, v, mx = 0;
if (f == -1) mi = N;
sun[u] = 1;
for (i = head[u];~i;i = e[i].ne) {
v = e[i].v;
if (vis[v] == ca || f == v) continue;
cal(v, u, s);
sun[u] += sun[v];
if (sun[v] > mx) mx = sun[v];
}
if (mx < s-sun[u]) mx = s-sun[u];
if (mx < mi) mi = mx, root = u;
}
void dfs(int u, int f, ll d, int id) {
int i, v;
sun[u] = 1;
if (d <= k) ans++;
V[id].push_back(d);
for (i = head[u];~i;i = e[i].ne) {
v = e[i].v;
if (vis[v] == ca || v == f) continue;
dfs(v, u, d+e[i].d, id);
sun[u] += sun[v];
}
}
void solve(int u, int sum) {
int v, i, j, id = 0, h;
cal(u, -1, sum);
vis[root] = ca;
// printf("[%d %d %d %lld]\n", u, sum, root, ans);
for (i = head[root];~i;i = e[i].ne) {
v = e[i].v;
if (vis[v] == ca) continue;
V[id].clear();
dfs(v, root, e[i].d*1ll, id);
sort(V[id].begin(), V[id].end());
id++;
}//printf("%lld\n", ans);
for (i = 0;i < id;i++) {
for (h = 0;h < V[i].size();h++) {
if (V[i][h] > k) break;
for (j = i+1;j < id;j++) {
int pos = upper_bound(V[j].begin(), V[j].end(), k-V[i][h])-V[j].begin();
ans += pos;
}
}
}
for (i = head[root];~i;i = e[i].ne) {
v = e[i].v;
if (vis[v] == ca) continue;
solve(v, sun[v]);
}
}
int main() {
int u, v, i, j, d;
char w;
while (~scanf("%d%d", &n, &m)) {
init();
while (m--) {
scanf("%d%d%d %c", &u, &v, &d, &w);
add(u, v, d), add(v, u, d);
}
scanf("%lld", &k);
ans = 0;
for (i = 1;i <= n;i++) {
if (vis[i] == ca) continue;
cal(i, -1, n);
solve(i, sun[i]);
}
ca++;
printf("%lld\n", ans);
}
}