【poj1741 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. 

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. 

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

题解:

  第一次写点分治感觉还好吧,对于一个子树先dfs预处理出sz(O(n)),然后dfs求出树的重心(O(n)),然后再分治下去(log)。

  计算答案时会算重,比如两个点都属于当前重心的一个子树,这两个点是不会通过当前重心的,所以要容斥删去。(记得每次寻找重心要初始化)

  怎么删,把重心的子节点再次计算减掉即可。

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 struct nd{
 8     int to,next,v;
 9 }    e[20005];
10 int head[10005],dep[10005],d[10005],mx[10005],sz[10005];
11 bool vis[10005];
12 int sum,ans,rt;
13 int n,k,cnt;
14 inline void insert(int u,int v,int w){
15     e[++cnt].next=head[u];
16     head[u]=cnt;
17     e[cnt].to=v;
18     e[cnt].v=w;
19 }
20 inline void findG(int now,int fa){
21     mx[now]=0;
22     for(int i=head[now];i;i=e[i].next){
23         if(e[i].to==fa || vis[e[i].to])    continue;
24         findG(e[i].to,now);
25         mx[now]=max(mx[now],sz[e[i].to]);
26     }
27     mx[now]=max(mx[now],sum-sz[now]);
28     if(mx[now]<mx[rt])    rt=now;
29 }
30 inline void findS(int now,int fa){
31     sz[now]=1;
32     for(int i=head[now];i;i=e[i].next){
33         if(vis[e[i].to] || e[i].to==fa)    continue;
34         findS(e[i].to,now);
35         sz[now]+=sz[e[i].to];
36     }
37 }
38 inline void findD(int now,int fa){
39     dep[++dep[0]]=d[now];
40     for(int i=head[now];i;i=e[i].next){
41         if(vis[e[i].to] || e[i].to==fa)    continue;
42         d[e[i].to]=d[now]+e[i].v;
43         findD(e[i].to,now);
44     }
45 }
46 inline int cal(int now,int x){
47     d[now]=x;dep[0]=0;
48     findD(now,-1);
49     sort(dep+1,dep+dep[0]+1);
50     int num=0,l,r;
51     for(int l=1,r=dep[0];l<r;){
52         if(dep[l]+dep[r]<=k){
53             num+=r-l;l++;
54         }
55         else    r--;
56     }
57     return num;
58 }
59 inline void work(int x)
60 {
61     ans+=cal(x,0);
62     vis[x]=1;
63     for(int i=head[x];i;i=e[i].next){
64         if(vis[e[i].to])    continue;
65         ans-=cal(e[i].to,e[i].v);
66         findS(e[i].to,x);
67         sum=sz[e[i].to];
68         rt=0;
69         findG(e[i].to,x);
70         work(rt);
71     }
72 }
73 int main(){
74     int u,v,w;
75     while(1){
76         ans=0,cnt=0;
77         memset(vis,0,sizeof(vis));
78         memset(head,0,sizeof(head));
79         scanf("%d%d",&n,&k);
80         if(!n)    return 0;
81         for(int i=1;i<n;i++){
82             scanf("%d%d%d",&u,&v,&w);
83             insert(u,v,w);
84             insert(v,u,w);
85         }
86         rt=0;
87         mx[rt]=1e9+7;
88         findS(1,-1);
89         sum=sz[1];
90         findG(1,-1);
91         work(rt);
92         printf("%d\n",ans);
93     }
94 }
posted @ 2017-11-27 21:59  LittleOrange  阅读(101)  评论(0编辑  收藏  举报