CF832D

题目链接:http://codeforces.com/contest/832/problem/D

题目大意:在一个无向图上,给出三个点,以其中一个点为终点,另外两个点为起点,请问如何安排起点和终点可以使得从两个起点走最短路到终点所共同经过的路径的长度最长?

解题思路:任取一个点作为根建立一棵树(为什么可以建成一棵树?它不会有环吗?请看题目中的这一句:“The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other.”),要求树中任意两点x,y的距离,其实只要先求出两点的公共祖先u,然后其距离便是 |depth[x]+depth[y]-2*depth[u]| 。对于一组确定的终点和起点,其共同路径长度就是 (dis(s1,t) + dis(s2,t) - dis(s1,s2))/2+1 (不理解的话稍微画一下图,至于为什么+1?根节点也要算哦亲)。具体请看代码(模板来自《挑战》)。

AC代码:

  

 1 #include <cstdio>
 2 #include <vector>
 3 #include <cmath>
 4 using namespace std;
 5 const int maxn=1e5+5;
 6 vector<int> G[maxn];
 7 int log_max_v;
 8 int parent[25][maxn];
 9 int depth[maxn],s[5];
10 int n,q;
11 void dfs(int v,int p,int d){
12     parent[0][v]=p;
13     depth[v]=d;
14     for(int i=0;i<G[v].size();i++){
15         if(G[v][i]!=p)  dfs(G[v][i],v,d+1);
16     }
17 }
18 void init(){
19     dfs(1,-1,0);
20     for(int k=0;k+1<20;k++){
21         for(int v=1;v<=n;v++){
22             if(parent[k][v]<0)  parent[k+1][v]=-1;
23             else parent[k+1][v]=parent[k][parent[k][v]];
24         }
25     }
26 }
27 int lca(int u,int v){
28     if(depth[u]>depth[v])   swap(u,v);
29     for(int k=0;k<20;k++){
30         if((depth[v]-depth[u])>>k&1){
31             v=parent[k][v];
32         }
33     }
34     if(u==v)    return u;
35     for(int k=20;k>=0;k--){
36         if(parent[k][u]!=parent[k][v]){
37             u=parent[k][u];
38             v=parent[k][v];
39         }
40     }
41     return parent[0][u];
42 }
43 int dis(int a,int b){
44     int u=lca(a,b);
45     return abs(depth[a]+depth[b]-depth[u]*2);
46 }
47 int main()
48 {
49     scanf("%d%d",&n,&q);
50     int p;
51     for(int i=2;i<=n;i++){
52         scanf("%d",&p);
53         G[i].push_back(p);
54         G[p].push_back(i);
55     }
56     init();
57     while(q--){
58         for(int i=0;i<3;i++)
59             scanf("%d",&s[i]);
60         
61         int ans=0;
62         for(int i=0;i<3;i++){
63             int a=(i+1)%3,b=(i+2)%3;
64             int temp=(dis(s[a],s[i])+dis(s[b],s[i])-dis(s[a],s[b]))/2;
65             if(temp>ans)    ans=temp;
66         }
67         printf("%d
",ans+1);
68     }
69 
70     return 0;
71 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/7348603.html