【描述】
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
解析:
这道题很显然要先缩边双连通分量 ,边双连通里面的边的代价是无效的。
显然一个联通无向图缩完
之后是一棵树。简单证明一下:
考虑如果不是一棵树,则必然有环(前提是图联通),那么这个环上每个点到其他点都有两条路径,则这个环必然是一个边双连通分量,可以继续缩。
缩 的方法就是缩 的方法魔改一下,我就不详细讲了。
然后就直接树形 ,每个节点维护三个值,最远儿子离他的距离 ,次远儿子离他的距离 ,这两个可以在第一次 搞定。(至于为什么要求次远儿子,马上讲解)。
而第二次 我们可以处理出经过这个点的父亲的最远点到它的距离,记为 。
最后 。
如何更新?
对于根节点,它的所有儿子中离他最远的就是他的答案。
我们这样用所有节点
去更新它的儿子。
如果这个儿子
不是最远儿子则对于这个儿子
。
而如果
是最远儿子,则
。因为不能走回头路。
这样就能 这道题了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=20004,M=200005;
int n,m;
int last[N],nxt[M<<1],to[M<<1],ecnt;
ll w[M<<1];
inline void addedge(int u,int v,ll val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
}
int dfn[N],low[N],dfn_clock;
int scc[N],scc_clock;
int sta[N],top;
bitset<N> insta;
inline void tarjan(int u,int fa){
dfn[u]=low[u]=++dfn_clock;
sta[++top]=u;
insta[u]=true;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(insta[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
++scc_clock;
re int x=sta[top];
while(x!=u){
scc[x]=scc_clock;
insta[x]=false;
x=sta[--top];
}
--top;
scc[x]=scc_clock;
insta[x]=false;
}
}
namespace TREE{
int last[N],nxt[N<<1],to[N<<1],ecnt;
ll w[N<<1];
inline void addedge(int u,int v,ll val){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
}
inline void _addedge(){
for(int re u=1;u<=n;++u){
for(int re e=::last[u],v=::to[e];e;v=::to[e=::nxt[e]])
if(scc[u]!=scc[v])addedge(scc[u],scc[v],::w[e]);
}
}
ll ans[N],sans[N],fans[N],subans[N];
int son[N],subson[N];
bitset<N> vis;
inline void dfs1(int u,int fa){
vis[u]=true;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa)continue;
dfs1(v,u);
re ll res=sans[v]+w[e];
if(res>sans[u]){
subson[u]=son[u];
subans[u]=sans[u];
son[u]=v,sans[u]=res;
}
else if(res>subans[u]){
subson[u]=v;
subans[u]=res;
}
}
}
inline void dfs2(int u,int fa){
ans[u]=max(sans[u],fans[u]);
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa)continue;
if(v==son[u])fans[v]=max(subans[u],fans[u])+w[e];
else fans[v]=max(sans[u],fans[u])+w[e];
dfs2(v,u);
}
}
inline void solve(){
for(int re i=1;i<=:scc_clock;++i){
if(!vis[i]){
dfs1(i,0);
dfs2(i,0);
}
}
}
}
signed main(){
n=getint();
m=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint();
ll val=getint();
addedge(u,v,val);
}
for(int re i=1;i<=n;++i)if(!dfn[i])tarjan(i,0);
TREE::_addedge();
TREE::solve();
for(int re i=1;i<=n;++i)outint(TREE::ans[scc[i]]),pc('\n');
return 0;
}