POJ 1741 Tree 树分治
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.
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.
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
题意:
给你一个含有n个节点的树,每条边有权值,问你有多少点对最短路径不超过k
题解:
树分治入门题
推荐看09年ioi的论文
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 1e5+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000; typedef long long ll; int n,m,root,t,ans,allnode,siz[N],K,head[N],vis[N],d[N]; int deep[N];//路径长度//deep[0]子节点个数 int f[N];//重心 struct edg{int to,next,v;}e[N * 4];//前向星存边 void add(int u,int v,int w) {e[t].to=v;e[t].next=head[u];e[t].v=w;head[u]=t++;}//加边 //获取重心 void getroot(int x,int fa) { siz[x] = 1; f[x] = 0; for(int i=head[x];i;i=e[i].next) { int to = e[i].to; if(to == fa || vis[to]) continue; getroot(to,x); siz[x] += siz[to]; f[x] = max(f[x] , siz[to]); } f[x] = max(allnode-siz[x] , f[x]); if(f[x] < f[root]) root = x; } void getdeep(int x,int fa) {//获取子树所有节点与根的距离 deep[++deep[0]] = d[x]; for(int i=head[x];i;i=e[i].next) { int to = e[i].to; if(to == fa || vis[to]) continue; d[to] = d[x] + e[i].v; getdeep(to,x); } } int cal(int x,int now) {//计算当前以重心x的子树下,所有情况的答案 d[x]=now;deep[0]=0; getdeep(x,0); sort(deep+1,deep+deep[0]+1); int all = 0; for(int l=1,r=deep[0];l<r;) { if(deep[l]+deep[r] <= K) {all += r-l;l++;} else r--; } return all; } void work(int x) {//以x为重心进行计算 vis[x] = 1; ans+=cal(x,0); for(int i=head[x];i;i=e[i].next) { int to = e[i].to; if(vis[to]) continue; ans -= cal(to,e[i].v); allnode = siz[to]; root=0; getroot(to,x); work(root); } } int main() { while(~scanf("%d%d",&n,&K)) { if(!n&&!m) break; memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); t = 1; for(int i=1;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c) , add(b,a,c); } root=ans=0; allnode=n;f[0]=inf; getroot(1,0); work(root); printf("%d\n",ans); } }