[SDOI2013]直径

题目大意:
  给你一棵n个结点的带边权的树,求该树直径必经边的个数。

思路:
  显然直径必经的所有边的肯定是一个直径上的连续一段。
  (若超过一段,则出现环,就不是树了)
  首先求出原树的任一直径。
  预处理出该直径上从结点i出发,不经过直径上其它结点的最长链长度far[i]。
  从直径的两端往里缩,如果当前缩到的点i的far[i]等于i到被缩的那一端的距离,就说明直径的这一段至少有两种不重合的情况,肯定不是必经部分。
  最后看一下中间没有被缩的部分经过了几个边。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 typedef long long int64;
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=200001;
13 struct Edge {
14     int to,w;
15 };
16 std::vector<Edge> e[N];
17 inline void add_edge(const int &u,const int &v,const int &w) {
18     e[u].push_back((Edge){v,w});
19     e[v].push_back((Edge){u,w});
20 }
21 bool mark[N];
22 int from[N],to[N],u,v;
23 int64 dis[N],far[N];
24 void dfs(const int &x) {
25     for(unsigned i=0;i<e[x].size();i++) {
26         const int &y=e[x][i].to,&w=e[x][i].w;
27         if(y==from[x]) continue;
28         from[y]=x;
29         dis[y]=dis[x]+w;
30         dfs(y);
31     }
32 }
33 void dp(const int &x,const int &par) {
34     for(unsigned i=0;i<e[x].size();i++) {
35         const int &y=e[x][i].to,&w=e[x][i].w;
36         if(y==par||mark[y]) continue;
37         dp(y,x);
38         far[x]=std::max(far[x],far[y]+w);
39     }
40 }
41 int main() {
42     const int n=getint();
43     for(register int i=1;i<n;i++) {
44         const int u=getint(),v=getint(),w=getint();
45         add_edge(u,v,w);
46     }
47     dfs(1);
48     for(register int i=1;i<=n;i++) {
49         if(dis[i]>dis[u]) u=i;
50     }
51     dis[u]=from[u]=0;
52     dfs(u);
53     for(register int i=1;i<=n;i++) {
54         if(dis[i]>dis[v]) v=i;
55     }
56     for(register int x=v;x;x=from[x]) {
57         mark[x]=true;
58         to[from[x]]=x;
59     }
60     for(register int x=v;x;x=from[x]) {
61         dp(x,0);
62     }
63     int l=u,r=v;
64     for(register int x=v;x;x=from[x]) {
65         if(far[x]==dis[v]-dis[x]) r=x;
66     }
67     for(register int x=u;x;x=to[x]) {
68         if(far[x]==dis[x]) l=x;
69     }
70     int len=0;
71     for(register int x=r,i=0;x;x=from[x],i++) {
72         if(x==l) len=i;
73     }
74     printf("%lld
%d
",dis[v],len);
75     return 0;
76 }
原文地址:https://www.cnblogs.com/skylee03/p/8081102.html