时间限制 : 20000 MS 空间限制 : 65536 KB
问题描述
Gremlins最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的地是牛棚_i)。每一个gremlin只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经。所以它们在牛_i到牛棚_i之前的最后一条牛路上等牛_i,当然,牛不愿意遇到Gremlins,所以准备找一条稍微不同的路经从牛棚_1走到牛棚_i,所以,请你为每一头牛_i找出避免gremlin_i的最短路经的长度。
和以往一样,农场上的M (2 <= M <= 200,000)条双向牛路编号为1..M并且能让所有牛到达它们的目的地,N(3 <= N <=100,000)个编号为1..N的牛棚。牛路i连接牛棚a_i (1 <= a_i <= N)和b_i (1 <= b_i <=N)并且需要时间t_i (1 <=t_i <=1,000)通过。没有两条牛路连接同样的牛棚,所有牛路满足a_i!=b_i。在所有数据中,牛_i使用的牛棚_1到牛棚_i的最短路经是唯一的。
以下是一个牛棚,牛路和时间的例子:
输入格式
第一行:两个空格分开的数N和M;
第2..M+1行:三个空格分开的数a_i, b_i,和t_i
输出格
第1..N-1行:第i行包含一个数,从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间。如果这样的路经不存在,输出-1。
样例输入
4 5
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3
样例输出
3
3
6
提示
20%的数据满足,N<=200;
50%的数据满足,N<=3000
100%的数据满足,N<=100,000
题解
本题中,奶牛们的原路径由从1号点出发到每个点的最短路组成,这提示我们可能需要建一棵最短路树,并在上面做点文章。显然,按照题目的要求,奶牛会经过不在最短路树上的另一条边绕过去。设我们要到的点为
k
k
,有一条不在最短路上的边为,
t=LCA(x,y)
t
=
L
C
A
(
x
,
y
)
,
k
k
在到
y
y
的路径上。那么奶牛绕行的距离可表示为,可以发现只要
dis[x]+len[x][y]+dis[y]
d
i
s
[
x
]
+
l
e
n
[
x
]
[
y
]
+
d
i
s
[
y
]
最小,所求答案就可最小。因此我们枚举不在最短路树的每一条边,更新两端点与
LCA
L
C
A
间的点即可(注意不能更新
LCA
L
C
A
)。显然可以树链剖分+线段树维护最小值。(图片引自何老板PPT)
顺便复习了一拨dijkstra+heap,才发现自己一直写的是SPFA式的假dijkstra……QAQ
代码
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> pii;
const int maxn=1e5+5;
const int inf=1e9;
int a,b,c,n,m,cnt=1,dis[maxn],fro[maxn],Last[maxn],St[maxn<<2],End[maxn<<2],Len[maxn<<2],Next[maxn<<2];
int vt,fa[maxn],dep[maxn],dfn[maxn],siz[maxn],son[maxn],top[maxn];
int lazy[maxn<<2],tree[maxn<<2];
bool vis[maxn],mark[maxn<<2];
priority_queue<pii,vector<pii>,greater<pii> > q;
void Addedge(int x,int y,int z)
{
End[++cnt]=y,St[cnt]=x,Len[cnt]=z;
Next[cnt]=Last[x],Last[x]=cnt;
}
void dijkstra(int x)
{
for(int i=1;i<=n;i++) dis[i]=inf;
dis[1]=0,q.push(make_pair(0,1));
while(!q.empty())
{
int x=q.top().second;q.pop();
if(vis[x]) continue;vis[x]=true;
for(int i=Last[x];i;i=Next[i])
{
int y=End[i];
if(dis[x]+Len[i]<dis[y])
{
dis[y]=dis[x]+Len[i],q.push(make_pair(dis[y],y));
mark[fro[y]]=false,fro[y]=i,mark[i]=true;
}
}
}
}
void Get_siz(int x)
{
dep[x]=dep[fa[x]]+1,siz[x]=1;
for(int i=Last[x];i;i=Next[i])
if(mark[i])
{
int y=End[i];
if(y==fa[x]) continue;
fa[y]=x,Get_siz(y),siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
void Get_dfn(int x,int anc)
{
if(!x) return;
dfn[x]=++vt,top[x]=anc;
Get_dfn(son[x],anc);
for(int i=Last[x];i;i=Next[i])
if(mark[i])
{
int y=End[i];
if(y==fa[x]||y==son[x]) continue;
Get_dfn(y,y);
}
}
namespace segment
{
void putdown(int p)
{
tree[p<<1]=min(tree[p<<1],lazy[p]);
tree[p<<1|1]=min(tree[p<<1|1],lazy[p]);
lazy[p<<1]=min(lazy[p<<1],lazy[p]);
lazy[p<<1|1]=min(lazy[p<<1|1],lazy[p]);
lazy[p]=inf;
}
void build(int p,int l,int r)
{
if(l<r)
{
int mid=(l+r)>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
tree[p]=lazy[p]=inf;
}
else tree[p]=lazy[p]=inf;
}
void modify(int p,int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)
{
lazy[p]=min(lazy[p],k),tree[p]=min(tree[p],k);
return;
}
if(lazy[p]<inf) putdown(p);
int mid=(l+r)>>1;
if(x<=mid&&y>=l) modify(p<<1,l,mid,x,y,k);
if(y>mid&&x<=r) modify(p<<1|1,mid+1,r,x,y,k);
}
int query(int p,int l,int r,int x)
{
if(l==r) return tree[p];
if(lazy[p]<inf) putdown(p);
int mid=(l+r)>>1;
if(x<=mid) return query(p<<1,l,mid,x);
return query(p<<1|1,mid+1,r,x);
}
}
int Get_lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) swap(x,y);
y=fa[top[y]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
void change(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) swap(x,y);
segment::modify(1,1,n,dfn[top[y]],dfn[y],z);
y=fa[top[y]];
}
if(dep[x]>dep[y]) swap(x,y);
segment::modify(1,1,n,dfn[x]+1,dfn[y],z);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
Addedge(a,b,c),Addedge(b,a,c);
}
dijkstra(1),Get_siz(1),Get_dfn(1,1);
segment::build(1,1,n);
for(int i=2;i<=cnt;i++)
if(!mark[i])
{
int lca=Get_lca(St[i],End[i]);
change(End[i],lca,dis[St[i]]+dis[End[i]]+Len[i]);
}
for(int i=2;i<=n;i++)
{
int temp=segment::query(1,1,n,dfn[i]);
if(temp<inf) printf("%d\n",temp-dis[i]);
else puts("-1");
}
return 0;
}