zoukankan      html  css  js  c++  java
  • SDOI2013直径(树的直径)

    题目描述:

    点这里

    题目大意:

    就是在一个树上找其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

    题解:

    首先,第一问很好求,两边dfs就行了,第一次从任一点找距它最远的点,再从这个点找距它的最远点,后两个点就是树的直径的两个端点,证明就不赘述了,有兴趣可以自己证一证玩一玩。

    那第二问怎么办呢?假设我们有这样一个图(如下)

    如图所示,中间那根直的就是树的直径之一,旁边标红的也是树的直径。(图画的不好,感性理解)

    我们要知道,树的直径是必定会有交叉的,可以画个图自己看一下。

    所以就会有一个想法:首先找出一条直径的起点,向终点推,如果碰到交叉,就看这个交叉是否是直径,如果是,就把第一个直径收缩,再继续找。再从终点向起点收缩一遍。剩下的边就是题目中要求的了。

    最后就是代码实现了,收缩的过程是真滴玄学。

    代码如下:

    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long 
    #define rint register int
    #define M 200005
    using namespace std;
    inline int read()
    {
        int s=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*f;
    }
    inline ll max(ll a,ll b){return a>b?a:b;}
    ll dis[M],maxx,s,t;
    ll n,m,cnt,head[M],vis[M];
    ll dep[M],father[M],l,r,ans,son[M];
    struct edge
    {
        int to,nex,v;       
    }e[M<<1];
    inline void add(int u,int v,int w)
    {
        e[++cnt].to=v;
        e[cnt].v=w;
        e[cnt].nex=head[u];
        head[u]=cnt;
    }
    void dfs(int u,int fa)
    {
        for(rint i=head[u];i;i=e[i].nex)
        {
            int v=e[i].to;if(v==fa) continue;father[v]=u;
            dis[v]=dis[u]+e[i].v;dfs(v,u);
        }
    }
    void find(int u,int fa)
    {
        dep[u]=0;ll maxn=0;
        for(rint i=head[u];i;i=e[i].nex)
        {
            int v=e[i].to;if(v==father[u] || vis[v]==1) continue;
            find(v,u);maxn=max(maxn,dep[v]+e[i].v);
        }
        dep[u]=maxn;
    }
    int main()
    {
        n=read();
        for(rint i=1;i<=n-1;++i)
        {
            int x=read(),y=read(),z=read();
            add(x,y,z),add(y,x,z);
        }
        dfs(1,0);
        for(rint i=1;i<=n;++i)
        {
            if(dis[i]>maxx) maxx=dis[i],s=i;
            dis[i]=0;
        }
        dfs(s,0);maxx=0;
        for(rint i=1;i<=n;++i)
        {
            if(dis[i]>maxx) maxx=dis[i],t=i;
        }
        printf("%lld
    ",maxx);
        int l=t,r=s,now=t;
        while(now!=s)
        {
            vis[now]=1;
            son[father[now]]=now;
            now=father[now];
        }
        now=t;
        while(now!=s)
        {
            dep[now]=0;
            find(now,0);
            if(dep[now]==maxx-dis[now]) l=now;
            now=father[now];
        }
        now=s;
        while(now)
        {
            find(now,0);
            if(dep[now]==dis[now]) r=now;
            now=son[now];
        }
        while(l!=r && l)
        {
            l=father[l];
            ++ans;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    谢谢大家!

  • 相关阅读:
    冲刺阶段九
    冲刺阶段八
    学习进度十一
    人月神话阅读笔记01
    单词统计续
    冲刺阶段七
    冲刺阶段六
    冲刺阶段五
    bzoj1570: [JSOI2008]Blue Mary的旅行
    bzoj 1690: [Usaco2007 Dec]奶牛的旅行
  • 原文地址:https://www.cnblogs.com/mxrmxr/p/10049410.html
Copyright © 2011-2022 走看看