【BZOJ】4144: [AMPPZ2014]Petrol

题意

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

分析

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

题解

根据分析,我们只需要按新赋值的边权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 @ 2015-11-22 18:30  iwtwiioi  阅读(1055)  评论(0编辑  收藏  举报