poj 1741 Tree

题意:给定一棵n节点的树(n<=10000),求满足dis(i,j)<=k的点数个数。

p.s.准备学习树链剖分。。先从qzc的论文开始。。

解法:树上分治。

   我们可以通过dfs求出每个点到子树根的距离,对于以u为根的子树,满足条件并且路径过u的点对数=满足条件的所有点对数-路径不过u的点对数。

   求法就是对所有dis排序然后两个指针扫,时间复杂度O(n).和http://acm.buaa.edu.cn:4567/problems/25一样的做法。

   当树退化的时候直接分治复杂度会很高,所以对于每个子树我们要找出重心,然后选重心为根再进行分治。这样的话递归深度会控制在log(n).

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define N 20010
 5 using namespace std;
 6 struct Edge{
 7     int u,v,len,next;
 8     Edge(){}
 9     Edge(int _u,int _v,int _len,int _next){
10         u=_u;v=_v;len=_len;next=_next;
11     }
12 }edge[N];
13 int head[N],cnt;
14 int root,Max;
15 int sz[N],maxn[N],dis[N],num;
16 bool vis[N];
17 int ans,n,k;
18 void init(){
19     memset(head,-1,sizeof(head));
20     memset(vis,0,sizeof(vis));
21     num=cnt=ans=0;
22 }
23 void dfs_size(int u,int pre){
24     int v;
25     sz[u]=1;
26     maxn[u]=0;
27     for(int k=head[u];k!=-1;k=edge[k].next){
28         v=edge[k].v;
29         if(v==pre||vis[v])continue;
30         dfs_size(v,u);
31         sz[u]+=sz[v];
32         maxn[u]=max(maxn[u],sz[v]);
33     }
34 }
35 void dfs_center(int x,int u,int pre){
36     if(sz[x]-sz[u]>maxn[u])maxn[u]=sz[x]-sz[u];
37     if(Max>maxn[u])Max=maxn[u],root=u;
38     for(int k=head[u];k!=-1;k=edge[k].next){
39         int v=edge[k].v;
40         if(v==pre||vis[v])continue;
41         dfs_center(x,v,u);
42     }
43 }
44 void dfs_dis(int u,int pre,int d){
45     dis[++num]=d;
46     for(int k=head[u];k!=-1;k=edge[k].next){
47         int v=edge[k].v;
48         if(v==pre||vis[v])continue;
49         dfs_dis(v,u,d+edge[k].len);
50     }
51 }
52 int cal(int u,int d){
53     int sum=0;
54     num=0;
55     dfs_dis(u,u,d);
56     sort(dis+1,dis+1+num);
57     int i=1,j=num;
58     while(i<j){
59         while(dis[i]+dis[j]>k&&i<j)j--;
60         sum+=j-i;
61         i++;
62     }
63     return sum;
64 }
65 void dfs(int u){
66     Max=n;
67     dfs_size(u,u);
68     dfs_center(u,u,u);
69     ans+=cal(root,0);
70     vis[root]=1;
71     for(int k=head[root];k!=-1;k=edge[k].next){
72         int v=edge[k].v;
73         if(vis[v])continue;
74         ans-=cal(v,edge[k].len);
75         dfs(v);
76     }
77 }
78 int main(){
79     while(~scanf("%d%d",&n,&k)){
80         if(!(n||k))return 0;
81         init();
82         for(int i=1;i<n;i++){
83             int u,v,len;
84             scanf("%d%d%d",&u,&v,&len);
85             edge[cnt]=Edge(u,v,len,head[u]);head[u]=cnt++;
86             edge[cnt]=Edge(v,u,len,head[v]);head[v]=cnt++;
87         }
88         dfs(1);
89         printf("%d\n",ans);
90     }
91     return 0;
92 }

 

posted @ 2013-02-07 22:22  silver__bullet  阅读(206)  评论(0编辑  收藏  举报