[SDOI2013] 直径

对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

Solution

有点意思

先随便求一条直径(两次DFS即可),不妨设为 (s,t),我们知道要求的这些边一定都在这条路径上,不妨将它看作一条线(用DFS + STACK把它提取出来),其中 (s) 叫左边, (t) 叫右边

我们现在就要在这条线上借出一段区间

考虑如何求它的右端点,以 (s) 为根跑 DFS,算出每个点子树的最长路径以及条数

(t) 往左扫,如果碰到某条边不是必须经过的边(可以根据 (u,v) 的最长路条数关系判断),就把它记下来

那么最后一次被记下来的边的左端点就是目标区间的右端点

左端点同理即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 200005;

vector <pair<int,int> > g[N];
int n,x[N],y[N],top;

namespace sol1 {
    int vis[N],dis[N],s,t,len;
    void dfs(int p) {
        vis[p]=1;
        for(int i=0;i<g[p].size();i++) {
            int q=g[p][i].first, w=g[p][i].second;
            if(vis[q]==0) {
                dis[q]=dis[p]+w;
                dfs(q);
            }
        }
    }
    void solve() {
        int tmp=0;
        dfs(1);
        for(int i=1;i<=n;i++) {
            if(dis[tmp]<dis[i]) tmp=i;
        }
        s=tmp;
        memset(vis,0,sizeof vis);
        memset(dis,0,sizeof dis);
        dfs(s);
        for(int i=1;i<=n;i++) {
            if(dis[tmp]<dis[i]) tmp=i;
        }
        t=tmp;
        len=dis[tmp];
    }
}

namespace sol2 {
    int vis[N],s,t;
    bool dfs(int p) {
        vis[p]=1;
        if(p==s) return 1;
        for(int i=0;i<g[p].size();i++) {
            int q=g[p][i].first, w=g[p][i].second;
            if(vis[q]==0) {
                int tmp = dfs(q);
                if(tmp) {
                    x[++top]=q;
                    y[top]=w;
                    return 1;
                }
            }
        }
    }
    void solve(int _s,int _t ){
        s=_s; t=_t;
        dfs(t);
        x[++top]=t;
    }
}

namespace sol3 {
    int vis[N],f[N],h[N];
    void dfs(int p) {
        vis[p]=1;
        h[p]=1;
        for(int i=0;i<g[p].size();i++) {
            int q=g[p][i].first, w=g[p][i].second;
            if(vis[q]==0) {
                dfs(q);
                if(f[p]<f[q]+w) {
                    f[p]=f[q]+w;
                    h[p]=0;
                }
                if(f[p]==f[q]+w) h[p]+=h[q];
            }
        }
    }
    int solve(int s) {
        dfs(s);
        int ans=top;
        //for(int i=1;i<=top;i++) cout<<h[x[i]]<<" ";
        //cout<<endl;
        for(int i=top-1;i;--i) {
            if(h[x[i]]!=h[x[i+1]]) ans=i;
        }
        return ans;
    }
}

namespace sol4 {
    int vis[N],f[N],h[N];
    void dfs(int p) {
        vis[p]=1;
        h[p]=1;
        for(int i=0;i<g[p].size();i++) {
            int q=g[p][i].first, w=g[p][i].second;
            if(vis[q]==0) {
                dfs(q);
                if(f[p]<f[q]+w) {
                    f[p]=f[q]+w;
                    h[p]=0;
                }
                if(f[p]==f[q]+w) h[p]+=h[q];
            }
        }
    }
    int solve(int s) {
        dfs(s);
        int ans=1;
        //for(int i=1;i<=top;i++) cout<<h[x[i]]<<" ";
        //cout<<endl;
        for(int i=2;i<=top;i++) {
            if(h[x[i]]!=h[x[i-1]]) ans=i;
        }
        return ans;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<n;i++) {
        int t1,t2,t3;
        cin>>t1>>t2>>t3;
        g[t1].push_back(make_pair(t2,t3));
        g[t2].push_back(make_pair(t1,t3));
    }
    sol1::solve();
    int s=sol1::s, t=sol1::t;
    sol2::solve(s,t);
    int ans1=sol3::solve(s);
    int ans2=sol4::solve(t);
    cout<<sol1::len<<endl<<ans1-ans2<<endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/12294846.html