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 }