树的直径相关

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

定理:

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

定理:

树 $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)$

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 }

时间: 2024-10-06 00:50:41

树的直径相关的相关文章

hdu 4123 Bob’s Race (树的直径相关+rmq+单调队列思想)

Bob's Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2115    Accepted Submission(s): 658 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble

poj 1985 Cow Marathon 【树的直径】

题目:poj 1985 Cow Marathon 题意:给出一个树,让你求树的直径. 分析: 树的直径:树上两点之间的最大距离. 我们从任意一点出发,BFS一个最远距离,然后从这个点出发,在BFS一个最远距离,就是树的直径. AC代码: /* POJ:1985 Cow Marathon 2014/10/12/21:18 Yougth*/ #include <cstdio> #include <iostream> #include <algorithm> #include

poj1849(求树的直径)

题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少? 分析:如果从某点出发遍历完一棵树再回来,那么所有边都会走两遍,而从某点有两个机器人出发去遍历,因为不用回来,所以最后那两个人距离越远越好,可以从树的直径上某个点背道而驰,那么这段距离(树的直径)只走了一遍,其他的要走两遍,所以ans=sum*2-l

SDUT OJ 3045 迷之图论 (树的直径)

题目地址:SDUT OJ 3045 这题比赛的时候想的差不多..但是总是觉得不对..写了一次就没再写,然后删了..当时没想到的是第二次求出来的就是最长链..当时想到的两次bfs找最大值(这一种方法其实结果也对..TAT..),还有找到点后在回溯减去重点等等..但总觉得好像都不太对...赛后才知道这题原来是树的直径.....牡丹江区域现场赛的时候遇到过,不过赛后也没看... 找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bf

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

ZOJ Problem Set - 3820 Building Fire Stations 【树的直径 + 操作 】

题目:problemId=5374" target="_blank">ZOJ Problem Set - 3820 Building Fire Stations 题意:给出n个点,n-1条边的一棵树.然后要在两个点上建立两个消防站.让全部点的到消防站最大距离的点的这个距离最小. 分析:首先先求这个树的直径.然后在树的直径的中点处把树分成两棵树.然后在把两棵树分别取中点的最大值就是ans值. 这个题目数据有点水了感觉... AC代码: #include <cstdi

BDFZOI 树的直径

提交次数:2 涉及知识:基础图论/BFS 描述 一棵树T的"直径"定义为结点两两间距离的最大值.给定带权树T,求T的直径长度. 输入 第一行包含2个整数N.M,表示图中共有N个结点和M条无向边.(N <= 5000,M<n)接下来M行,每行包含3个整数{u,v,w},表示有一条无向边连接结点u.v*输入保证是无环图输出一个整数,代表直径长度 样例输入 4 31 2 12 3 22 4 3 样例输出 5 代码: 1 #include<iostream> 2 #in

codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径

题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” consists of n servers and m two-way communication links. Two servers can communicate either through a direct link, or through a chain of links, by relayi

hdu 4607(树的直径)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 题解:给定一棵树,从树中的任意选一个顶点出发,遍历K个点的最短距离是多少?(每条边的长度为1) 算法分析: 首先如果k小于等于直径长度,那么答案为k−1;如果k大于直径长度,设直径长度为r,那么答案为r−1+(k−r)*2;树的直径:树上的最长简单路径; 代码: 1 #include <cstdio> 2 #include <cmath> 3 #include <cstri