[题解] [BZOJ4144] 「AMPPZ2014」Petrol

题面

怎么是权限题啊

题解

有一次考过, 但是不记得了

如果每个点都是加油站的话, 这道题就是货车运输

考虑如何转化

我们可以设𝑑𝑖𝑠[𝑖]为𝑖到离他最近的加油站的距离, 𝑖𝑑[𝑖]记录的是离𝑖最近的加油站是哪一个

最短路转移即可

然后对于原图中每一条边(𝑢,𝑣,𝑤), 若𝑖𝑑[𝑢]≠𝑖𝑑[𝑣], 则连一条(𝑖𝑑[𝑢],𝑖𝑑[𝑣],𝑑𝑖𝑠[𝑢]+𝑑𝑖𝑠[𝑣]+𝑤)的边

将边与询问一起离线存下来, 排序后(连边的优先度高于询问)并查集维护, 若对于一个询问的两个端点不在同一个联通块, 输出NIE, 否则输出TAK

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 400005
#define mk(i, j) make_pair(i, j)
#define rint register int
using namespace std;

int n, m, s, head[N], cnt, tot, dis[N], pos[N], id[N], fa[N], Q, ans[N], rnk[N];
struct edge { int from, to, next, cost; } e[N << 1];
struct node
{
	int u, v, w, opt, id;
	bool operator < (const node &p) const
		{
			return w < p.w || (w == p.w && opt < p.opt); 
		}
} a[N << 1]; 
bool vis[N];
priority_queue<pair <int, int> > q; 

template < typename T >
inline T read()
{
	T x = 0, w = 1; char c = getchar();
	while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * w; 
}

inline void adde(int u, int v, int w) { e[++cnt] = (edge) { u, v, head[u], w }; head[u] = cnt; }

void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	for(rint i = 1; i <= s; i++)
		q.push(mk(dis[pos[i]] = 0, pos[i])), id[pos[i]] = pos[i];
	while(!q.empty())
	{
		int u = q.top().second; q.pop();
		vis[u] = 1;
		for(int v, i = head[u]; i; i = e[i].next)
		{
			v = e[i].to;
			if(dis[v] > dis[u] + e[i].cost && !vis[v])
			{
				dis[v] = dis[u] + e[i].cost, id[v] = id[u];
				q.push(mk(-dis[v], v)); 
			}
		}
	}
}

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void merge(int x, int y)
{
	x = find(x), y = find(y);
	if(rnk[x] < rnk[y]) fa[x] = y;
	else if(rnk[x] > rnk[y]) fa[y] = x;
	else fa[y] = x, rnk[x]++; 
}

void solve()
{
	for(rint i = 1; i <= n; i++)
		fa[i] = i, rnk[i] = 1; 
	sort(a + 1, a + tot + 1);
	for(rint i = 1; i <= tot; i++)
		if(a[i].opt) ans[a[i].id] = find(a[i].u) == find(a[i].v);
		else merge(a[i].u, a[i].v); 
}

int main()
{
	n = read <int> (), s = read <int> (), m = read <int> ();
	for(rint i = 1; i <= s; i++)
		pos[i] = read <int> ();
	for(rint u, v, w, i = 1; i <= m; i++)
		u = read <int> (), v = read <int> (), w = read <int> (), adde(u, v, w), adde(v, u, w);
	dijkstra(); 
	for(rint u, v, w, i = 1; i <= cnt; i += 2)
		a[++tot] = (node) { id[u = e[i].from], id[v = e[i].to], w = dis[u] + dis[v] + e[i].cost, 0, 0 }; 
	Q = read <int> ();
	for(rint u, v, w, i = 1; i <= Q; i++)
		a[++tot] = (node) { u = read <int> (), v = read <int> (), w = read <int> (), 1, i };
	solve();
	for(rint i = 1; i <= Q; i++)
		puts(ans[i] ? "TAK" : "NIE"); 
	return 0; 
}
posted @ 2019-11-06 17:16  ztlztl  阅读(103)  评论(0编辑  收藏  举报