zoukankan      html  css  js  c++  java
  • 【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集

    【BZOJ1576】[Usaco2009 Jan]安全路经Travel

    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
    输入解释:
    跟题中例子相同

    Sample Output

    3
    3
    6
    输出解释:
    跟题中例子相同

    题解: 先求出最短路径树,然后我们统计每条非树边对每个点的影响。一条非树边可以更新它覆盖的所有点,如果这条边(x,y,len)覆盖了z,那么ans[z]=min(ans[z],dis[x]+dis[y]+len-dis[z]),因为dis[z]是确定的,所以我们维护链上的dis[x]+dis[y]+len的最小值即可。

    如何维护?树剖+线段树,倍增,都是不错的方案,当然有更巧的。将所有非树边按dis[x]+dis[y]+len从小到大排序,然后用并查集维护所有没被更新的点,暴力更新路径上没被更新的点即可。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <utility>
    #define mp(A,B) make_pair(A,B)
    using namespace std;
    const int maxn=100010;
    int n,m,cnt;
    int to[maxn<<2],next[maxn<<2],val[maxn<<2],head[maxn],dis[maxn],fa[maxn],pre[maxn];
    int f[maxn],s[maxn],ans[maxn];
    bool vis[maxn];
    priority_queue<pair<int,int> > q;
    struct edge
    {
    	int a,b,v;
    	bool ont;
    }p[maxn<<1];
    inline char nc()
    {
    	static char buf[100000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=nc();
    	while(!isdigit(gc))	{if(gc=='-')	f=-f;	gc=nc();}
    	while(isdigit(gc))	ret=ret*10+gc-'0',gc=nc();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    bool cmp(const edge &a,const edge &b)
    {
    	return a.v<b.v;
    }
    int find(int x)
    {
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    int main()
    {
    	n=rd(),m=rd();
    	memset(head,-1,sizeof(head));
    	register int i,u,a,b;
    	for(i=1;i<=m;i++)	p[i].a=rd(),p[i].b=rd(),p[i].v=rd(),add(p[i].a,p[i].b,p[i].v),add(p[i].b,p[i].a,p[i].v);
    	memset(dis,0x3f,sizeof(dis));
    	dis[1]=0,q.push(mp(0,1));
    	while(!q.empty())
    	{
    		u=q.top().second,q.pop();
    		if(vis[u])	continue;
    		vis[u]=1;
    		for(i=head[u];i!=-1;i=next[i])	if(dis[to[i]]>dis[u]+val[i])
    			fa[to[i]]=u,pre[to[i]]=(i>>1)+1,dis[to[i]]=dis[u]+val[i],q.push(mp(-dis[to[i]],to[i]));
    	}
    	for(i=1;i<=n;i++)	f[i]=i,p[pre[i]].ont=1;
    	for(i=1;i<=m;i++)	p[i].v+=dis[p[i].a]+dis[p[i].b];
    	sort(p+1,p+m+1,cmp);
    	for(i=1;i<=m;i++)	if(!p[i].ont)
    	{
    		a=find(p[i].a),b=find(p[i].b);
    		while(a!=b)
    		{
    			if(dis[a]<dis[b])	swap(a,b);
    			ans[a]=p[i].v-dis[a],f[a]=fa[a],a=find(f[a]);
    		}
    	}
    	for(i=2;i<=n;i++)	printf("%d
    ",(!ans[i])?-1:ans[i]);
    	return 0;
    }

     

  • 相关阅读:
    关于ie7下display:inline-block;不支持的解决方案。
    Unicode转义序列
    DOMContentLoaded与load的区别
    有关列分组,定义css样式无效的问题
    多行文字溢出[...]的实现(text-overflow: ellipsis)
    goahead cgi 及出现的问题解决
    Android面试题整理(1)
    回溯法 之 马周游(马跳日)问题
    软件工程总结
    [置顶] 每日震精图
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7671047.html
Copyright © 2011-2022 走看看