Processing math: 100%

【BZOJ】4144: [AMPPZ2014]Petrol

题意

给定一个n个点、m条边的带权无向图,其中有s个点是加油站。每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。(2sn200000,1m200000

分析

首先来分析如果只有一个询问,给出x点和y点问x是否能走到y。假设经过的非加油站的点集依次是p1,p2,,pk,那么考虑从p1走到p2,假设有边(p1,p2)(否则一定是从加油站走到p2的),权值为w。如果我们从p1走到最近的加油站(距离为d(p1))加满油再回来,还剩的油为bd(p1),然后再走这条边。而如果直接从p1走到p2,由于没有加油,此时在p1的油量显然是bd(p1)的。显然加了油更优。

题解

根据分析,我们只需要按新赋值的边权w+d(u)+d(v)生成最小生成树来判断即可。对于询问,离线一下即可。

#include <bits/stdc++.h>
using namespace std;
const int N=200005, M=200005;
int ihead[N], cnt, n, m, s, p[N], h[N], c[N];
struct E {
	int next, to, w;
}e[M<<1];
struct ED {
	int x, y, d;
}ed[M];
struct QU {
	int x, y, b, id;
}q[N];
void add(int x, int y, int w) {
	e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt;
	e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt;
}
int find(int x) {
	return x==p[x]?x:p[x]=find(p[x]);
}
typedef pair<int, int> pii;
#define mkpii make_pair<int, int>
priority_queue<pii, vector<pii>, greater<pii> > qu;
int d[N], vis[N];
void dij() {
	memset(d, 0x7f, sizeof(int)*(n+1));
	for(int i=0; i<s; ++i) {
		d[c[i]]=0;
		qu.push(mkpii(0, c[i]));
	}
	while(qu.size()) {
		int x=qu.top().second;
		qu.pop();
		if(vis[x]) {
			continue;
		}
		vis[x]=1;
		for(int i=ihead[x]; i; i=e[i].next) {
			int y=e[i].to;
			if(d[y]>d[x]+e[i].w) {
				d[y]=d[x]+e[i].w;
				qu.push(mkpii(d[y], y));
			}
		}
	}
}
inline bool cmp1(const ED &a, const ED &b) {
	return a.d<b.d;
}
inline bool cmp2(const QU &a, const QU &b) {
	return a.b<b.b;
}
int ans[N];
int main() {
	scanf("%d%d%d", &n, &s, &m);
	for(int i=1; i<=n; ++i) {
		p[i]=i;
		h[i]=1;
	}
	for(int i=0; i<s; ++i) {
		scanf("%d", &c[i]);
	}
	for(int i=0; i<m; ++i) {
		scanf("%d%d%d", &ed[i].x, &ed[i].y, &ed[i].d);
		add(ed[i].x, ed[i].y, ed[i].d);
	}
	dij();
	for(int i=0; i<m; ++i) {
		ed[i].d+=d[ed[i].x]+d[ed[i].y];
	}
	int Q;
	scanf("%d", &Q);
	for(int i=0; i<Q; ++i) {
		scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].b);
		q[i].id=i;
	}
	sort(ed, ed+m, cmp1);
	sort(q, q+Q, cmp2);
	int now=0;
	for(int i=0; i<Q; ++i) {
		while(now<m && ed[now].d<=q[i].b) {
			int fx=find(ed[now].x), fy=find(ed[now].y);
			if(fx!=fy) {
				if(h[fx]>h[fy]) {
					swap(fx, fy);
				}
				p[fx]=fy;
				h[fy]+=h[fy]==h[fx];
			}
			++now;
		}
		ans[q[i].id]=find(q[i].x)==find(q[i].y);
	}
	for(int i=0; i<Q; ++i) {
		puts(ans[i]?"TAK":"NIE");
	}
	return 0;
}
posted @   iwtwiioi  阅读(1091)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示