[SDOI2013] 直径

题目描述

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。

路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。

直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。

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

输入输出格式

输入格式:

第一行包含一个整数N,表示节点数。 接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c的无向边。

输出格式:

共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有直径经过的边的数量。

输入输出样例

输入样例#1: 复制
8
0 1 1
1 2 2
2 3 3
3 4 4
3 7 4
2 6 3
1 8 1

输出样例#1: 复制

10
1

说明

【样例说明】 直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。

对于100%的测试数据:2<=N<=200000,所有点的编号都在1..N的范围内,边的权值<=10^9。

Soultion

本题一看就是树的直径(题目都说了),它要求所有直径都经过的边的数量。
先看样例的图,把直径给标出来。

直径是1,2,3,4,7,直径长度为10,我们枚举直径上的点,只要验证是否存在一个长度,等于之前的长度就行啦。我们枚举到1,发现8可以替换0,所以8,2,3,47形成新的直径,显然1,2之间这条边不可能是重合的边,就这样推过去,可以发现只有中间的边是重合的边,但是我们需要判断当前这个点是往左走,还是往右走,例如8这个点,显然走往3,不会往1走,6是往4走,5是往3走。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long lol;
struct node
{
    lol to,next,w;
}a[500100];
lol len,last[500010],fa[501010],vis[501001],ans[501010],d[501010],l,r;
lol rr,ll;
void add(lol a1,lol a2,lol a3)
{
    a[++len].to=a2;
    a[len].w=a3;
    a[len].next=last[a1];
    last[a1]=len;
}
void dfs(lol x,lol father)
{
    for(lol i=last[x];i;i=a[i].next)
    {
        lol to=a[i].to;
        if(to==father||vis[to]) continue;
        fa[to]=x;
        d[to]=d[x]+a[i].w;
        dfs(to,x);
    }
}
void dfs1(lol x,lol father,lol id)
{
    for(lol i=last[x];i;i=a[i].next)
    {
        
        lol to=a[i].to;
        if(to==father||vis[to]) continue;
        d[to]=d[x]+a[i].w;
        if(d[to]==ans[id]||d[to]==ans[r]-ans[id])
        rr=id;
        dfs1(to,x,id);
    }
}
void dfs2(lol x,lol father,lol id)
{
    for(lol i=last[x];i;i=a[i].next)
    {
        
        lol to=a[i].to;
        if(to==father||vis[to]) continue;
        d[to]=d[x]+a[i].w;
        if(d[to]==ans[id]||d[to]==ans[r]-ans[id])
        if(!ll)
        ll=id;
        dfs2(to,x,id);
    }
}
int main()
{
    lol n,x,y,z;
    cin>>n;
    for(lol i=1;i<n;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&z);
        add(x,y,z);add(y,x,z);
    }
    dfs(1,0);
    for(lol i=1;i<=n;i++) if(d[i]>d[l]) l=i;
    memset(fa,0,sizeof(fa));memset(d,0,sizeof(d));
    dfs(l,0);
    for(lol i=1;i<=n;i++) if(d[i]>d[r]) r=i;
    for(lol i=r;i;i=fa[i]) vis[i]=1,ans[i]=d[i];
    cout<<d[r]<<endl;
    memset(d,0,sizeof(d));
    for(lol i=fa[r];fa[i]!=0;i=fa[i])
    {
        if(ans[i]*2>ans[r])
        dfs1(i,0,i);
        else
        dfs2(i,0,i);
    }
    lol pp=0,p=0;
//	cout<<ll<<' '<<rr<<endl;
    for(lol i=r;fa[i];i=fa[i])
    p++;
    if(ll==0)
    {
        for(int i=rr;fa[i]!=0;i=fa[i])
        pp++;
        cout<<pp<<endl;
    }
    else if(rr==0)
    {
        for(int i=r;i!=ll;i=fa[i])
        pp++;
        cout<<pp;
    }
    else
    {
        for(int i=rr;i!=ll;i=fa[i])
        pp++;
        cout<<pp<<endl;
    }
}

博主蒟蒻,可以随意转载,但必须附上原文链接k-z-j

posted @ 2018-08-19 21:58  k-z-j  阅读(220)  评论(0编辑  收藏  举报