[BZOJ1468]Tree
[BZOJ1468]Tree
试题描述
给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K
输入
N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k
输出
一行,有多少对点之间的距离小于等于k
输入示例
7 1 6 13 6 3 9 3 5 7 4 1 3 2 4 20 4 7 2 10
输出示例
5
数据规模及约定
见“输入”
题解
又来一道裸点分治,分别统计重心下面每一颗子树的路径长度和整棵树的路径长度,二分一下算方案数,去重。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
#define maxn 40010
#define maxm 80010
int n, m, K, head[maxn], next[maxm], to[maxm], dist[maxm], ans;
void AddEdge(int a, int b, int c) {
to[++m] = b; dist[m] = c; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; dist[m] = c; next[m] = head[a]; head[a] = m;
return ;
}
bool vis[maxn];
int root, size, f[maxn], siz[maxn];
void getroot(int u, int fa) {
siz[u] = 1; f[u] = 0;
for(int e = head[u]; e; e = next[e]) if(!vis[to[e]] && to[e] != fa) {
getroot(to[e], u);
siz[u] += siz[to[e]];
f[u] = max(f[u], siz[to[e]]);
}
f[u] = max(f[u], size - siz[u]);
if(f[root] > f[u]) root = u;
return ;
}
int A[maxn], tot, B[maxn], ToT;
void dfs(int u, int fa, int d) {
if(d > K) return ;
A[++tot] = d;
for(int e = head[u]; e; e = next[e]) if(!vis[to[e]] && to[e] != fa)
dfs(to[e], u, d + dist[e]);
return ;
}
void solve(int u) {
// printf("u: %d\n", u);
vis[u] = 1;
ToT = 0;
int sum = 0;
for(int e = head[u]; e; e = next[e]) if(!vis[to[e]]) {
tot = 0;
dfs(to[e], u, dist[e]);
sort(A + 1, A + tot + 1);
ans += tot;
// for(int i = 1; i <= tot; i++) printf("%d ", A[i]); putchar('\n');
for(int i = 1; i <= tot; i++) {
int k = upper_bound(A + 1, A + tot + 1, K - A[i]) - A - 1;
sum += k;
// printf("%d ", k);
}
// puts("end");
for(int i = 1; i <= tot; i++) B[++ToT] = A[i];
}
// printf("here: %d ", sum);
int tmp = 0;
sort(B + 1, B + ToT + 1);
for(int i = 1; i <= ToT; i++) {
int k = upper_bound(B + 1, B + ToT + 1, K - B[i]) - B - 1;
tmp += k;
}
// printf("%d\n", tmp);
ans += (tmp - sum >> 1);
for(int e = head[u]; e; e = next[e]) if(!vis[to[e]]) {
root = 0; f[0] = n + 1; size = siz[u]; getroot(to[e], u);
solve(root);
}
return ;
}
int main() {
n = read();
for(int i = 1; i < n; i++) {
int a = read(), b = read(), c = read();
AddEdge(a, b, c);
}
K = read();
root = 0; f[0] = n + 1; size = n; getroot(1, 0);
solve(root);
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号