zoukankan      html  css  js  c++  java
  • 免费航班

    Description

    小Z在MOI比赛中获得了大奖,奖品是一张特殊的机票。使用这张机票,可以在任意一个国家内的任意城市之间的免费飞行,只有跨国飞行时才会有额外的费用。小Z获得了一张地图,地图上有城市之间的飞机航班和费用。已知从每个城市出发能到达所有城市,两个城市之间可能有不止一个航班。一个国家内的每两个城市之间一定有不止一条飞行路线,而两个国家的城市之间只有一条飞行路线。小Z想知道,从每个城市出发到额外费用最大的城市,以便估算出出行的费用,请你帮助他。当然,你不能通过乘坐多次一个航班增加额外费用,也就是必须沿费用最少的路线飞行。

    Input

    第一行,两个整数N,M,表示地图上有N个城市,M条航线。
    接下来M行,每行三个整数a,b,c,表示城市a,b之间有一条费用为c的航线。

    Output

    共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

    Hint

    样例说明
    有四个国家,包含的城市分别为 {1,2,3},{4},{5},{6}。从城市1出发到达城市6,乘坐(1,3)(3,6)两个航班费用最大,(1,3)在国内为免费航班,(3,6)的费用为4,所以从1出发的最大费用为4。

    数据规模
    对于30%的数据 1<=N<=1000,1<=M<=1000
    对于100%的数据 1<=N<=20000,1<=M<=200000


    正解:tarjan求双连通分量+树型dp

    tarjan找出桥,用并查集维护每个双连通分量,然后把每个双连通分量缩成一个点,重构一个图。这时我们发现这个图变成了一棵树,然后我们就可以用树型dp。先用一遍dfs求出每个点在它子树内的距离最大值,然后用bfs求出每个点子树外的距离最大值,然后我们就可以算出答案了。

    //It is made by wfj_2048~
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #define inf 1<<30
    #define il inline
    #define RG register
    #define ll long long
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    
    using namespace std;
    
    struct edge{ int nt,to,dis; }G[400010],g[400010];
    
    int Head[100010],head[100010],size[100010],fa[100010],child[100010],dfn[100010],low[100010],vi[100010],vis[100010],dis[100010],sondis[100010],updis[100010],premax[100010],sufmax[100010],ans[100010],bl[100010],q[100010],st[100010],n,m,num,Num,tot,cnt,block;
    
    il int gi(){
        RG int x=0,q=0; RG char ch=getchar();
        while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=1,ch=getchar();
        while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
    }
    
    il void insert(RG int from,RG int to,RG int dis){ g[++num]=(edge){head[from],to,dis},head[from]=num; }
    
    il void Insert(RG int from,RG int to,RG int dis){ G[++Num]=(edge){Head[from],to,dis},Head[from]=Num; }
    
    il int father(RG int x){ if (fa[x]!=x) fa[x]=father(fa[x]); return fa[x]; }
    
    il void unionn(RG int u,RG int v){
        RG int a=father(u),b=father(v); if (a==b) return;
        if (size[a]<size[b]) fa[a]=b,size[b]+=size[a];
        else fa[b]=a,size[a]+=size[b]; return;
    }
    
    il void tarjan(RG int x,RG int p){
        dfn[x]=low[x]=++cnt,vis[x]=1,st[++tot]=x;
        for (RG int i=head[x];i;i=g[i].nt){
    	RG int v=g[i].to;
    	if (!vis[v]){
    	    tarjan(v,x); low[x]=min(low[x],low[v]);
    	    if (dfn[x]>=low[v]) unionn(x,v);
    	}else if (v!=p) low[x]=min(low[x],low[v]);
        }
        return;
    }
    
    il void dfs(RG int x){
        vis[x]=n+1; RG int v;
        for (RG int i=head[x];i;i=g[i].nt){
    	v=g[i].to; if (bl[x]!=bl[v]) Insert(bl[x],bl[v],g[i].dis);
    	if (vis[v]!=n+1) dfs(v);
        }
        return;
    }
    
    il void find(RG int x,RG int p){
        for (RG int i=Head[x];i;i=G[i].nt){
    	RG int v=G[i].to; if (v==p) continue; find(v,x);
    	sondis[x]=max(sondis[x],sondis[v]+G[i].dis);
        }
        return;
    }
    
    il void bfs(RG int rt){
        RG int h=0,t=1; q[t]=rt,ans[rt]=sondis[rt],vi[rt]=1;
        while (h<t){
    	RG int x=q[++h]; tot=0;
    	for (RG int i=Head[x];i;i=G[i].nt)
    	    if (!vi[G[i].to]){
    		q[++t]=G[i].to,vi[G[i].to]=1;
    		child[++tot]=G[i].to,dis[tot]=G[i].dis;
    	    }
    	premax[0]=sufmax[tot+1]=0;
    	for (RG int i=1;i<=tot;++i) premax[i]=max(premax[i-1],sondis[child[i]]+dis[i]);
    	for (RG int i=tot;i;--i) sufmax[i]=max(sufmax[i+1],sondis[child[i]]+dis[i]);
    	for (RG int i=1;i<=tot;++i){
    	    updis[child[i]]=max(premax[i-1],sufmax[i+1])+dis[i];
    	    updis[child[i]]=max(updis[child[i]],updis[x]+dis[i]);
    	    ans[child[i]]=max(updis[child[i]],sondis[child[i]]);
    	}
        }
        return;
    }
    
    il void work(){
        n=gi(),m=gi(); RG int u,v,w; num=1; for (RG int i=1;i<=n;++i) fa[i]=i,size[i]=1;
        for (RG int i=1;i<=m;++i) u=gi(),v=gi(),w=gi(),insert(u,v,w),insert(v,u,w);
        tarjan(1,0); for (RG int i=1;i<=n;++i) if (father(i)==i) block++,bl[i]=block;
        for (RG int i=1;i<=n;++i) bl[i]=bl[father(i)];
        dfs(1); find(1,0); bfs(1);
        for (RG int i=1;i<=n;++i) printf("%d
    ",ans[bl[i]]); return;
    }
    
    int main(){
        File("flight");
        work();
        return 0;
    }
    



  • 相关阅读:
    第九章 统一连贯的段落 《英语科技写作(文法与修辞原则)》by 方克涛
    第八章 通顺的句子 《英语科技写作(文法与修辞原则)》by 方克涛
    CMake使用操作解析参考1
    发一个SharePoint修改好式样的菜单导航
    Jquery Ajax学习实例4向WebService发出请求,返回实体对象的异步调用
    修改SharePoint网站最大上载大小时有时需要关注的事项
    轻松Ajax.net实例教程13_TextBoxWatermarkExtender(按AjaxControlToolkit字母排序)
    Jquery Ajax学习实例2向页面发出请求,返回JSon格式数据
    Jquery Ajax学习实例3向WebService发出请求,调用方法返回数据
    CSS语法学习总结
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6416601.html
Copyright © 2011-2022 走看看