树的直径相关

真的还有好多东西要学啊......

 

定理:

  选取树 $T$ 的任意一个点 $i$ ,则与 $i$ 距离最远的节点 $r$ 必定是树中一条直径的端点.

 

定理:

  经过树上一点i的最长路径的长度,一定等于:

  情况1. $i$ 所引领的子树中,最大深度与次大深度之和.

  情况2. $i$ 所引领的子树中的最大深度,加上 $i$ 到 $j$ 的最长路径,其中 $j$ 是一个不属于 $i$ 这个子树的节点.

  当 $i$ 是树根时, $i$ 没有父节点,于是只会是情况1.

 

定理:

  树 $T$ 的直径长度一定能表示为树 $T$ 上某个点 $i$ 所引领的子树中,最大深度与次大深度之和.

  即, $\exists_{i\in V(T)}\; diameter = LargestDepth(subtree \ o \! f \ i) + SecondLargestDepth(subtree \ o \! f \ i)$

  由于直径只有一个值,并且两个深度之和代表了一条路径的长度,

  于是有$\forall_{i\in V(T)} \; diameter \ge LargestDepth(subtree \ o \! f \ i) + SecondLargestDepth(subtree \ o \! f \ i)$

 

定理:

  点 $i$ 在某条直径上,当且仅当存在一条经过点 $i$ 的路径,它的长度(大于)等于直径.

 

AC VIJOS 1476 求在直径上的所有点. 直径可能有多条.

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42  
 43 db eps=1e-80;
 44 inline bool feq(db a,db b)
 45 { return fabs(a-b)<eps; }
 46 
 47 template<typename Type>
 48 inline Type avg(const Type a,const Type b)
 49 { return a+((b-a)/2); }
 50 
 51 //===================================================================
 52 //===================================================================
 53 //===================================================================
 54 //===================================================================
 55 
 56 
 57 const int INF=(1<<30)-1;
 58 
 59 struct edge
 60 {
 61     int in;
 62     edge*nxt;
 63 }pool[405000];
 64 edge*et=pool;
 65 edge*eds[205000];
 66 void addedge(int i,int j)
 67 { et->in=j; et->nxt=eds[i]; eds[i]=et++; }
 68 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
 69 
 70 int n;
 71 
 72 int dep[205000];
 73 int q[205000],qh,qt;
 74 
 75 int deg[205000];
 76 
 77 int dia=0;
 78 
 79 int mx[205000];
 80 int mxs[205000];
 81 int mxp[205000];
 82 int uv[205000];
 83 
 84 int f[205000];
 85 
 86 int main()
 87 {
 88     n=getint();
 89     for(int i=1;i<n;i++)
 90     {
 91         int a=getint();
 92         int b=getint();
 93         addedge(a,b);
 94         addedge(b,a);
 95     }
 96     
 97     qh=qt=0;
 98     q[qt++]=0;
 99     memset(dep,0xFF,sizeof(int)*(n+1));
100     dep[0]=0;
101     while(qh!=qt)
102     {
103         int x=q[qh];
104         FOREACH_EDGE(i,x)
105         if(dep[i->in]==-1)
106         {
107             f[i->in]=x;
108             dep[i->in]=dep[x]+1;
109             q[qt++]=i->in;
110             deg[x]++;
111         }
112         qh++;
113     }
114     
115     memset(mxp,0xFF,sizeof(int)*(n+1));
116     memset(mx,0xFF,sizeof(int)*(n+1));
117     memset(mxs,0xFF,sizeof(int)*(n+1));
118     qh=qt=0;
119     for(int i=0;i<n;i++)
120     if(deg[i]==0) q[qt++]=i;
121     while(qh!=qt)
122     {
123         int x=q[qh];
124         
125         FOREACH_EDGE(i,x)
126         if(i->in!=f[x])
127         {
128             if(mx[i->in]>mx[x])
129             {
130                 mxs[x]=mx[x];
131                 mx[x]=mx[i->in];
132                 mxp[x]=i->in;
133             }
134             else if(mx[i->in]>mxs[x])
135             {
136                 mxs[x]=mx[i->in];
137             }
138         }
139         
140         deg[f[x]]--;
141         if(deg[f[x]]==0)
142         { q[qt++]=f[x]; }
143         
144         mx[x]++;
145         mxs[x]++;
146         
147         qh++;
148     }
149     
150     qh=qt=0;
151     uv[0]=0;
152     FOREACH_EDGE(i,0)
153     q[qt++]=i->in;
154     
155     while(qh!=qt)
156     {
157         int x=q[qh];
158         
159         uv[x]=max( uv[f[x]],
160                  x==mxp[f[x]] ? mxs[f[x]] : mx[f[x]]) +1;
161         
162         FOREACH_EDGE(i,x)
163         if(i->in!=f[x]) q[qt++]=i->in;
164         
165         qh++;
166     }
167     
168     for(int i=0;i<n;i++)
169     dia=max(dia,mx[i]+mxs[i]);
170     
171     
172     for(int i=0;i<n;i++)
173     if(mx[i]+uv[i]==dia || mx[i]+mxs[i]==dia) printf("%d\n",i);
174     
175     return 0;
176 }
View Code

自底向上DP的思路很巧妙.注意两个条件都要判断.

 

posted @ 2015-04-02 21:55  DragoonKiller  阅读(224)  评论(0编辑  收藏  举报