[题解] [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;
}