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

    谢谢大家!

  • 相关阅读:
    398. Random Pick Index
    382. Linked List Random Node
    645. Set Mismatch
    174. Dungeon Game
    264. Ugly Number II
    115. Distinct Subsequences
    372. Super Pow
    LeetCode 242 有效的字母异位词
    LeetCode 78 子集
    LeetCode 404 左叶子之和
  • 原文地址:https://www.cnblogs.com/mxrmxr/p/10049410.html
Copyright © 2011-2022 走看看