[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;
}

 

posted @ 2016-09-25 21:37  xjr01  阅读(156)  评论(0编辑  收藏  举报