bzoj千题计划134:bzoj3124: [Sdoi2013]直径

http://www.lydsy.com/JudgeOnline/problem.php?id=3124

 

第一问:

dfs1、dfs2

dfs2中记录dis[i]表示点i距离最长链左端点的距离

第二问:

所有直径的交集一定是最长链上连续的一段

dfs3记录最长链,

从最长链上每个点i开始dfs4,记录能到达的非最长链点的最远距离mx

如果mx==最长链-dis[i],更新交集的左端点

如果mx==dis[i],找到交集的右端点,退出

 

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;
#define N 200001

int tot;
int front[N],nxt[N<<1],to[N<<1],val[N<<1];

LL mx,max_len;
int wh;

LL dis[N]; 

int path[N],num;

bool use[N];

int cf[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c))  c=getchar(); 
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
}

void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
}

void dfs1(int x,int y,LL d)
{
    if(d>mx) mx=d,wh=x;
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==y) continue;
        dfs1(to[i],x,d+val[i]);
    }
}

void dfs2(int x,int y,LL d)
{
    dis[x]=d;
    if(d>max_len) max_len=d,wh=x;
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==y) continue;
        dfs2(to[i],x,d+val[i]);
    }
}

void dfs3(int x,LL d)
{
    path[++num]=x; 
    use[x]=true;
    for(int i=front[x];i;i=nxt[i])
    {
        if(dis[to[i]]==d-val[i]) dfs3(to[i],d-val[i]);
    }
}

void dfs4(int x,int y,LL d)
{
    mx=max(mx,d);
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==y || use[to[i]]) continue;
        dfs4(to[i],x,d+val[i]);
    }
}

int main()
{
    int n;
    read(n);
    int u,v,w;
    for(int i=1;i<n;++i)
    {
        read(u); read(v); read(w);
        add(u,v,w);
    }
    dfs1(1,0,0);
    dfs2(wh,0,0);
    cout<<max_len<<'\n';
    dfs3(wh,max_len);
    int L=1,R=num;
    for(int i=2;i<num;++i)
    {
        mx=0;
        dfs4(path[i],0,0);
        if(mx==max_len-dis[path[i]]) L=i;
        if(mx==dis[path[i]]) { R=i; break; }
    }    
    cout<<R-L;
}

 

3124: [Sdoi2013]直径

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1261  Solved: 603
[Submit][Status][Discuss]

Description

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)
表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。  
 直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。 
现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。 

Input

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

Output

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

Sample Input


6
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100

Sample Output

1110
2


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

HINT

 

对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,

 

边的权值≤10^9。

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8038444.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值