1576: [Usaco2009 Jan]安全路经Travel
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1044 Solved: 363
[Submit][Status][Discuss]
Description
Input
* 第一行: 两个空格分开的数, N和M
* 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i
Output
* 第1..N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间.如果这样的路经不存在,输出-1.
Sample Input
4 5
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3
输入解释:
跟题中例子相同
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3
输入解释:
跟题中例子相同
Sample Output
3
3
6
输出解释:
跟题中例子相同
3
6
输出解释:
跟题中例子相同
HINT
Source
Solution
比较简单的一道题
首先我们跑一遍最短路,得到最短路树,在松弛操作的时候加一句话即可
然后我们发现对于不在最短路树上的边,如果把它加入树中,会形成一个环,它会影响这个环上除lca的其他点
样例是这样的,黑边是指最短路树上的边,加入非树红边,影响的是红点,加入非树蓝边,有影响的是蓝点
所发生的影响就是,环上点x,在加入边<u,v>会被更新成dis[u]+dis[v]+val<u,v>-dis[x]
所以要求被更新后最小,就是要求dis[u]+dis[v]+val<u,v>最小,那么我们按照这个价值对非树边排序
从权值小的开始更新。
所以这样的话,中间会更新一些重复的,我们只要保证那些重复的不被更新即可,这个显然可以利用并查集维护一下
这样时间复杂度大概是$O(nlogn+n×a(n))$
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 100010 #define MAXM 200010 int N,M; struct EdgeNode{int next,to,t,from;}edge[MAXM<<1]; int head[MAXN],cnt=1; void AddEdge(int u,int v,int w) {cnt++; edge[cnt].from=u; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].t=w;} void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);} #define Pa pair<int,int> #define INF 0x7fffffff priority_queue<Pa,vector<Pa>,greater<Pa> >q; int dis[MAXN],fa[MAXN]; void Dijkstra(int S) { for (int i=1; i<=N; i++) dis[i]=INF; q.push(make_pair(0,S)); dis[S]=0; while (!q.empty()) { int now=q.top().second; int Dis=q.top().first; q.pop(); if (Dis>dis[now]) continue; for (int i=head[now]; i; i=edge[i].next) if (Dis + edge[i].t < dis[edge[i].to]) dis[edge[i].to]=Dis+edge[i].t, fa[edge[i].to]=now, q.push(make_pair(dis[edge[i].to],edge[i].to)); } } int f[MAXN]; int F(int x) {if (!f[x]) return x; else return f[x]=F(f[x]);} struct RoadNode { int u,v,t; bool operator < (const RoadNode & A) const {return t<A.t;} }road[MAXM]; int tot,num; int ans[MAXN]; void Add(RoadNode x) { int u=x.u,v=x.v,t=x.t; while (F(u)!=F(v)) { num++; if (dis[F(u)]<dis[F(v)]) swap(u,v); ans[F(u)]=min(ans[F(u)],t-dis[F(u)]); u=f[F(u)]=fa[F(u)]; } } int main() { N=read(),M=read(); for (int x,y,z,i=1; i<=M; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z); Dijkstra(1); for (int i=2; i<=cnt; i+=2) { int u=edge[i].from,v=edge[i].to; if (fa[u]!=v && fa[v]!=u) road[++tot].u=u,road[tot].v=v,road[tot].t=dis[u]+dis[v]+edge[i].t; } sort(road+1,road+tot+1); // for (int i=1; i<=tot; i++) // printf("%d %d %d ",road[i].u,road[i].v,road[i].t); // for (int i=1; i<=N; i++) printf("%d ",dis[i]); puts(""); for (int i=1; i<=N; i++) ans[i]=INF; for (int i=1; i<=tot && num<N-1; i++) Add(road[i]); for (int i=2; i<=N; i++) printf("%d ",ans[i]==INF? -1:ans[i]); return 0; }
写完就A了....