【NOIP校内模拟】航班

【描述】
L因为业务繁忙,经常会到处出差。因为他是航空公司的优质客户,于是某个航空
公司给了他一个优惠券。
他可以利用这个优惠券在任何一个国家内的任意城市间免费旅行,当他的路线跨国
才会产生费用。 L有一个航空公司的价格表与航线。而且每个城市出发都能到所有的城
市, 2 个城市间可能有不止一个航班,一个国家内的 2个城市间一定有不同的路线,但是
不同国家的城市间只有一条路线。 L想知道从每个城市出发到产生费用最多的城市,不过
你不能重复在一个航班上飞来飞去产生费用,不行沿最少的费用路线飞行。
【输入】
第一行,两个整数 N,M,表示 N 个城市, M 条航线。
接下来 M 行,每行三个整数 a,b,c,表示城市 a,b 之间有一条费用为 c 的航
线。
【输出】
共 N 行,第 i 行为从城市 i 出发到达每个城市额外费用的最大值。
【Sample Input】
6 6
1 4 2
1 2 6
2 5 3
2 3 7
6 3 4
3 1 8
【Sample Output】
4 4 4 6 7 7
【解释】
有四个国家,包含的城市分别为 {1,2,3},{4},{5},{6}。
从城市 1 出发到达城市 6,乘坐(1,3)(3,6)两个航班费用最大, (1,3)在国内为免费航
班, (3,6)的费用为 4,所以从 1 出发的最大费用为 4。
【数据规模】
对于 40%的数据 1<=N<=1000,1<=M<=1000
对于 100%的数据 1<=N<=20000,1<=M<=200000

首先,在一个国家的城市肯定属于同一个边双联通分量,因此我们对于无向图跑一遍tarjan,然后缩点

现在整个图变成了一颗树,相当于就是让我们求一个点在树上的最长距离是多少

先求出树的直径,设端点为A,B,那么每个点的最长距离就是max(dis[A],dis[B])

可以用反证法来证明,假如最长距离是到点C,那么树的直径就会变化了

代码很好实现,只需两发dfs即可

#include<bits/stdc++.h>
#define N 20005
#define M 200005
using namespace std;
struct Edge
{
    int to,next,val;
}edge[2*M];
int first[N],tot;
int n,m;
inline void addedge(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=first[x];
    edge[tot].val=z;
    first[x]=tot;
}
stack <int> sta;
bool insta[N];
int dfn[N],low[N],sign,num,belong[N];
void dfs(int now,int fa)
{
    dfn[now]=low[now]=++sign;
    insta[now]=true;
    sta.push(now);
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(vis==fa) continue;
        if(!dfn[vis]){
            dfs(vis,now);
            low[now]=min(low[now],low[vis]);
        }
        else if(insta[vis]) low[now]=min(low[now],dfn[vis]);
    }
    if(dfn[now]==low[now])
    {
        int top;
        num++;
        do
        {
            top=sta.top();
            insta[top]=false;
            belong[top]=num;
            sta.pop();
        }
        while(top!=now);
    }
}
struct SCC
{
    int to,next,val;
}scc[2*M];
int head[N];
inline void addscc(int x,int y,int z)
{
    tot++;
    scc[tot].to=y;
    scc[tot].next=head[x];
    scc[tot].val=z;
    head[x]=tot;
}
int maxdis,disA[N],disB[N],point;
void dfs1(int now,int fa)
{
    for(int u=head[now];u;u=scc[u].next)
    {
        int vis=scc[u].to;
        if(vis==fa) continue;
        disA[vis]=disA[now]+scc[u].val;
        if(disA[vis]>maxdis)
        {
            maxdis=disA[vis];
            point=vis;
        }
        dfs1(vis,now);
    }
}
void dfs2(int now,int fa)
{
    for(int u=head[now];u;u=scc[u].next)
    {
        int vis=scc[u].to;
        if(vis==fa) continue;
        disB[vis]=disB[now]+scc[u].val;
        dfs2(vis,now);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL),cout.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        addedge(a,b,c);
        addedge(b,a,c);
    }
    for(int i=1;i<=n;i++)   if(!dfn[i]) dfs(i,0);
    tot=0;
    for(int i=1;i<=n;i++)
    {
        for(int u=first[i];u;u=edge[u].next)
        {
            int vis=edge[u].to;
            if(belong[i]!=belong[vis])  addscc(belong[i],belong[vis],edge[u].val);
        }
    }
    dfs1(1,-1);
    memset(disA,0,sizeof(disA)),maxdis=0;
    dfs1(point,-1);
    dfs2(point,-1);
    for(int i=1;i<=n;i++)   cout<<max(disA[belong[i]],disB[belong[i]])<<'\n';
    return 0;
}

转载于:https://www.cnblogs.com/Patrickpwq/articles/9743582.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值