• 【BZOJ4144】[AMPPZ2014]Petrol(最短路+最小生成树+并查集)


    Description
    给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
    每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
    q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。
    Input
    第一行包含三个正整数n,s,m(2<=s<=n<=200000,1<=m<=200000),表示点数、加油站数和边数。
    第二行包含s个互不相同的正整数c[1],c[2],...cs,表示每个加油站。
    接下来m行,每行三个正整数u[i],v[i],di,表示u[i]和v[i]之间有一条长度为d[i]的双向边。
    接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
    接下来q行,每行包含三个正整数x[i],y[i],bi,表示一个询问。
    Output
    输出q行。第i行输出第i个询问的答案,如果可行,则输出TAK,否则输出NIE。
    Sample Input
    6 4 5
    1 5 2 6
    1 3 1
    2 3 2
    3 4 3
    4 5 5
    6 4 5
    4
    1 2 4
    2 6 9
    1 5 9
    6 5 8
    Sample Output
    TAK
    TAK
    TAK
    NIE

    题解

    居然是权限题……

    不难发现我们需要的是加油站之间的最短路,然而肯定不能直接跑否则会(gg)

    考虑一条边((u,v)),如果我们要从加油站(a)(b),且这条路经过((u,v)),设(c)为到(u)最近的加油站,(d)为到(v)最近的加油站,最优策略肯定是从(a)(c),从(c)(d),从(d)(b),因为这里面每一次的加油站之间的转移的距离都要小于从(a)直接走到(b)

    那么我们可以做一个多源最短路,记录(las_i)表示离(i)最近的加油站,(dis_i)表示(i)(las_i)的距离

    对于一条边((u,v)),如果(las_u=las_v),那么这条边显然对加油站之间的最短路是无所谓的

    否则的话,我们在新图中加入边((las_u,las_v,dis_u+dis_v+(u,v)))

    那么把询问离线,按边权排序,用最小生成树和并查集解决就行了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=2e5+5;
    struct eg{int v,nx,w;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
    struct node{
    	int u,d;
    	node(){}
    	node(R int u,R int d):u(u),d(d){}
    	inline bool operator <(const node &b)const{return d>b.d;}
    };priority_queue<node>q;
    struct EG{
    	int u,v,w,id;
    	EG(){}
    	EG(R int u,R int v,R int w,R int id=0):u(u),v(v),w(w),id(id){}
    	inline bool operator <(const EG &b)const{return w<b.w;}
    }E[N],Q[N];
    int dis[N],las[N],vis[N],fa[N],ans[N],n,m,s,qaq,u,v,w,cnt;
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void merge(R int u,R int v){
    	u=find(u),v=find(v);
    	fa[u]=v;
    }
    int main(){
    	freopen("petrol.in","r",stdin);
    	freopen("petrol.out","w",stdout);
    	memset(dis,0x3f,sizeof(dis));
    	n=read(),s=read(),m=read();
    	fp(i,1,s)u=read(),las[u]=u,dis[u]=0,q.push(node(u,0));
    	fp(i,1,m)u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
    	while(!q.empty()){
    		int u=q.top().u;q.pop();
    		if(vis[u])continue;vis[u]=1;
    		go(u)if(cmin(dis[v],dis[u]+e[i].w))las[v]=las[u],q.push(node(v,dis[v]));
    	}
    	fp(u,1,n)go(u)if(las[u]<las[v])E[++cnt]=EG(las[u],las[v],dis[u]+dis[v]+e[i].w);
    	sort(E+1,E+1+cnt);
    	qaq=read();
    	fp(i,1,qaq)Q[i].u=read(),Q[i].v=read(),Q[i].w=read(),Q[i].id=i;
    	sort(Q+1,Q+1+qaq);
    	fp(i,1,n)fa[i]=i;
    	for(R int i=1,j=1;i<=qaq;++i){
    		while(j<=cnt&&E[j].w<=Q[i].w)merge(E[j].u,E[j].v),++j;
    		ans[Q[i].id]=(find(Q[i].u)==find(Q[i].v));
    	}
    	fp(i,1,qaq)puts(ans[i]?"TAK":"NIE");
    	return 0;
    }
    
  • 相关阅读:
    卡诺图简单逻辑化简与五变量卡诺图化简
    flash读写学习笔记与spi接口及简单测试验证(三)
    疯狂的订餐系统软件需求分析挑战之旅4
    .NET(C#):谈谈各种结束进程的方法
    疯狂的订餐系统软件需求分析挑战之旅3
    疯狂的订餐系统软件需求分析挑战之旅5
    找零
    ASP.NET MVC3 Razor视图引擎基础语法
    做了8年软件开发了,年龄大了,想要转行做测试,大家给点意见
    想搞一个 代码仓库的东西,不知道大家有没有兴趣啊
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10361536.html
Copyright © 2020-2023  润新知