[POI2008]Station

题目大意:
  给定一棵n个结点的树,求一个点x作为根,使得所有结点到x的距离和最小。

思路:
  树形DP。
  首先考虑将1作为根的情况。
  很显然我们可以用一遍O(n)的DFS预处理出每个结点所对应子树大小size和子树内每个结点到这个结点的距离和sum。
  这样也就相当于我们递推求出了以1作为根时各结点到它的距离和。
  现在考虑将根往下转移。
  假设我们现在要从u转移到v,那么显然在sum[u]的基础上,sum[v]需要变化的是(u,v)之间的连接的边。
  也就是说sum[y]=sum[x]+n-size[y]*2。
  这样我们就可以用O(n)时间将根往下转移。
  总的时间复杂度还是O(n)的。

 1 #include<cstdio>
 2 #include<cctype>
 3 typedef long long int64;
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=1000001;
12 int head[N],to[N<<1],next[N<<1],sz;
13 inline void add_edge(const int &u,const int &v) {
14     to[++sz]=v; next[sz]=head[u]; head[u]=sz;
15     to[++sz]=u; next[sz]=head[v]; head[v]=sz;
16 }
17 int64 sum[N],max;
18 int n,size[N],root;
19 void dfs(const int &x,const int &par) {
20     size[x]=1;
21     for(int i=head[x];i;i=next[i]) {
22         const int &y=to[i];
23         if(y==par) continue;
24         dfs(y,x);
25         size[x]+=size[y];
26         sum[x]+=sum[y]+size[y];
27     }
28 }
29 void move(const int &x,const int &par) {
30     if(sum[x]>max) {
31         max=sum[x];
32         root=x;
33     } else if(sum[x]==max&&x<root) {
34         root=x;
35     }
36     for(int i=head[x];i;i=next[i]) {
37         const int &y=to[i];
38         if(y==par) continue;
39         sum[y]=sum[x]+n-size[y]*2;
40         move(y,x);
41     }
42 }
43 int main() {
44     n=getint();
45     for(register int i=1;i<n;i++) {
46         add_edge(getint(),getint());
47     }
48     dfs(1,0);
49     move(1,0);
50     printf("%d\n",root);
51     return 0;
52 }

 

posted @ 2017-12-15 19:38  skylee03  阅读(112)  评论(0编辑  收藏  举报