LightOJ1257 Farthest Nodes in a Tree (II)(树的点分治)

题目给一棵树,边带有权值,求每一点到其他点路径上的最大权和。

树上任意两点的路径都可以看成是经过某棵子树根的路径,即路径权=两个点到根路径权的和,于是果断树分治。

对于每次分治的子树,计算其所有结点到根的距离;对于每个结点,找到另一个离根最远的且与该结点路径过根的结点,二者的距离和就是这个点在过这棵子树的根能到的最远距离。

现在问题就是怎么比较快地找到这另一个最远距离的点。。两点路径过根,说明两点间不存在一点是另一点的祖先。。我一开始还想用DFS序+线段树来着。。想了想,想出了线性的算法:

记录每个结点属于根的哪个儿子,把当前分治子树的所有结点以属于根的哪个儿子分组,对于每个结点对应过根的结点就不能在同一组要到别的组找,而且肯定是某个组里面根距离最大的值的那个结点。通过计算每个组里面结点到根的最大值作为组的值,以及这些组的最大值和次大值,就OK了。

好难描述= =反正这样这题就用树分治解决了,时间复杂度O(nlogn)。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm> 
  4 using namespace std;
  5 #define INF (1<<29)
  6 #define MAXN 33333
  7 struct Edge{
  8     int u,v,w,next;
  9 }edge[MAXN<<1];
 10 int NE,head[MAXN];
 11 void addEdge(int u,int v,int w){
 12     edge[NE].u=u; edge[NE].v=v; edge[NE].w=w;
 13     edge[NE].next=head[u]; head[u]=NE++;
 14 }
 15 
 16 bool vis[MAXN];
 17 
 18 int size[MAXN];
 19 void getSize(int u,int fa){
 20     size[u]=1;
 21     for(int i=head[u]; i!=-1; i=edge[i].next){
 22         int v=edge[i].v;
 23         if(vis[v] || v==fa) continue;
 24         getSize(v,u);
 25         size[u]+=size[v];
 26     }
 27 }
 28 int centre,mini;
 29 void getCentre(int u,int fa,int &tot){
 30     int res=tot-size[u];
 31     for(int i=head[u]; i!=-1; i=edge[i].next){
 32         int v=edge[i].v;
 33         if(vis[v] || v==fa) continue;
 34         getCentre(v,u,tot);
 35         res=max(res,size[v]);
 36     }
 37     if(mini>res){
 38         mini=res;
 39         centre=u;
 40     }
 41 }
 42 int getCentre(int u){
 43     getSize(u,u);
 44     mini=INF;
 45     getCentre(u,u,size[u]);
 46     return centre;
 47 }
 48 
 49 int n,ans[MAXN];
 50 int dn,dx[MAXN],dy[MAXN],mx1,mx2,belong[MAXN],mx[MAXN];
 51 void dfs(int u,int fa,int dist,int &gp){
 52     dx[dn]=u; dy[dn]=dist; dn++;
 53     belong[u]=gp;
 54     mx[gp]=max(mx[gp],dist);
 55     for(int i=head[u]; i!=-1; i=edge[i].next){
 56         int v=edge[i].v;
 57         if(vis[v] || v==fa) continue;
 58         dfs(v,u,dist+edge[i].w,gp);
 59     }
 60 }
 61 void conquer(int u){
 62     dn=0; mx1=0; mx2=-INF;
 63     dx[dn]=u; dy[dn]=0; dn++;
 64     belong[u]=u;
 65     for(int i=head[u]; i!=-1; i=edge[i].next){
 66         int v=edge[i].v;
 67         if(vis[v]) continue;
 68         mx[v]=-INF;
 69         dfs(v,u,edge[i].w,v);
 70         if(mx1<mx[v]) mx2=mx1,mx1=mx[v];
 71         else if(mx2<mx[v]) mx2=mx[v];
 72     }
 73     for(int i=0; i<dn; ++i){
 74         if(mx[belong[dx[i]]]!=mx1) ans[dx[i]]=max(ans[dx[i]],dy[i]+mx1);
 75         else ans[dx[i]]=max(ans[dx[i]],dy[i]+mx2);
 76     }
 77 }
 78 
 79 void divide(int u){
 80     u=getCentre(u);
 81     vis[u]=1;
 82     conquer(u);
 83     for(int i=head[u]; i!=-1; i=edge[i].next){
 84         int v=edge[i].v;
 85         if(vis[v]) continue;
 86         divide(v);
 87     }
 88 }
 89 int main(){
 90     int t,a,b,c;
 91     scanf("%d",&t);
 92     for(int cse=1; cse<=t; ++cse){
 93         NE=0;
 94         memset(head,-1,sizeof(head));
 95         scanf("%d",&n);
 96         for(int i=1; i<n; ++i){
 97             scanf("%d%d%d",&a,&b,&c);
 98             addEdge(a,b,c); addEdge(b,a,c);
 99         }
100         memset(vis,0,sizeof(vis));
101         for(int i=0; i<n; ++i) ans[i]=-INF;
102         divide(0);
103         printf("Case %d:\n",cse);
104         for(int i=0; i<n; ++i) printf("%d\n",ans[i]);
105     }
106     return 0;
107 }

 

posted @ 2016-03-05 23:07  WABoss  阅读(583)  评论(0编辑  收藏  举报