免费航班

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\n",ans[bl[i]]); return;
}

int main(){
    File("flight");
    work();
    return 0;
}



posted @ 2017-01-22 18:59  wfj_2048  阅读(123)  评论(0编辑  收藏  举报