青少年是一个美好而又是一去不可再得的时期,是将来一切光明和幸福的开端。——加里宁
这道题是经典的点分,拿来练练手。
题目大意:
一行n,m范围是100000。(n是树的节点树木,m是树上链长度上限)
下面n-1行每行三个数给定树,(前两个给定树的边,后一个为长度)。
注意:是多组数据,最后两个0 0结束。
然后询问树上不超过m的链的个数。
Example:
IN PUT:
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
OUT PUT:
8
具体实现:
我们每次进行点分(求重心),然后对链进行处理,咋处理呢。
因为一条链必定在重心的两颗不同的子树内(易证得),所以大体思想是求出所有点到重心的距离,然后求出所有满足不大于m的链的个数,最后减去一个子树内的个数。
详见代码:
//
// main.cpp
// POJ 1741
//
// Created by apple on 17/3/20.
// Copyright © 2017年 apple. All rights reserved.
//
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
struct Edge{
int v, next, w;
};
Edge e[2 * N];
int n, m, head[N], num, x, y, z, vis[N], siz[N], f[N], sum, root, dis[N], tot, ans;
void adde( int i, int j, int w ) {
e[++num].v = j;
e[num].next = head[i];
e[num].w = w;
head[i] = num;
}
void init() {//初始化
memset( head, 0, sizeof(head) );
memset( vis, 0, sizeof(vis) );
for ( int i = 1; i < n; i++ ) {
scanf( "%d%d%d", &x, &y, &z );
adde( x, y, z );
adde( y, x, z );
}
}
void getroot( int u, int fa ) {//求树的重心
siz[u] = 1; f[u] = 0;
for ( int i = head[u]; i; i = e[i].next ) {
int v = e[i].v;
if ( v == fa || vis[v] ) continue;
getroot(v, u);
siz[u] += siz[v];
f[u] = max( f[u], siz[v] );
}
f[u] = max(f[u], sum-siz[u]);
if ( f[u] < f[root] ) root = u;
}
void getdis( int u, int d, int fa ) {//求点到重心的距离
dis[++tot] = d;
for ( int i = head[u]; i; i = e[i].next ) {
int v = e[i].v;
if ( v == fa || vis[v] ) continue;
getdis(v, d+e[i].w, u);
}
}
int calc( int u, int d ) {//计算满足要求的个数
int ret = 0;
tot = 0;
getdis(u, d, 0);
sort(dis+1, dis+tot+1);
int i = 1, j = tot;
while ( i < j ) {//经典的双向
if ( dis[i] + dis[j] <= m && i < j ) {
ret += ( j - i );
i++;
}
else j--;
}
return ret;
}
void solv( int u ) {
ans += calc( u, 0 );//加上所有满足要求
vis[u] = 1;
for ( int i = head[u]; i; i = e[i].next ) {
int v = e[i].v;
if ( vis[v] ) continue;
ans -= calc(v, e[i].w);//减去在同一个子树内的个数
sum = siz[v];//求重心的初始化
root = 0;
getroot(v, 0);
solv(root);//递归解决
}
}
int main() {
while (1) {
ans = 0;
scanf("%d%d", &n, &m);
if ( n == 0 && m == 0 ) break;
init();
sum = n;
root = 0;
f[0] = 0x3f3f3f3f;
getroot(1, 0);
solv(root);
printf( "%d\n", ans );
}
return 0;
}
完毕!
附上我对你的思念。