Description
雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路。
雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予的能量为Wi。
如果城市u和v之间有一条道路,那么只要此刻雪之女王的能量不小于|Wu-Wv|,这条道路就是安全的。
如果城市u和v之间存在两条没有重复道路的安全路径(其中每一段道路都是安全的),则认为这两座城市之间有着良好的贸易关系。
最近,雪之女王因为情感问题,她的能量产生巨大的波动。为了维持雪之国度的经济贸易,她希望你能帮忙对Q对城市进行调查。
对于第j对城市uj和vj,她希望知道在保证这两座城市之间有着良好贸易关系的前提之下,自己最少需要保持多少的能量。
Solution
我们先用Kruskal搞出一棵最小生成树,然后将没有用到的边按权值大小从小到大依次加入。
新加入的边所覆盖的点可以搞进同一个并查集,如果询问的两个点在同一个并查集,那么答案就是当前加入的边的权值。
我们可以用类似Kruskal重构树类似的思想,每次合并时新建一个点连向要合并的两个部分,询问的时候找到两个点的LCA即可。
Code
/************************************************
* Au: Hany01
* Date: Sep 13th, 2018
* Prob: 51nod1743 雪之国度
* Email: hany01dxx@gmail.com & hany01@foxmail.com
* Inst: Yali High School
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define ALL(a) a.begin(), a.end()
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
static int _, __; static char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 1e5 + 5, maxm = 5e5 + 5;
int n, dep[maxn << 1], Fa[19][maxn << 1], vis[maxn << 1], use[maxm], val[maxn], clk, top[maxn], cur, W[maxn], fa[maxn], rt[maxn];
vector<int> T[maxn], NT[maxn << 1];
struct Edge {
int u, v, w;
bool operator < (const Edge& rhs) const { return w < rhs.w; }
}E[maxm];
struct DSU {
int fa[maxn];
inline void init() { For(i, 1, n) fa[i] = i; }
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inline bool merge(int u, int v) { return ((u = find(u)) ^ (v = find(v))) ? fa[u] = v, 1 : 0; }
}dsu;
void getDepth(int u, int pa) {
dep[u] = dep[pa] + 1, fa[u] = pa;
for (int v: T[u]) if (v != pa) getDepth(v, u);
}
void DFS(int u) {
vis[u] = clk;
for (int v: NT[u]) {
Fa[0][v] = u, dep[v] = dep[u] + 1;
For(i, 1, 18) Fa[i][v] = Fa[i - 1][Fa[i - 1][v]];
DFS(v);
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
Fordown(i, 18, 0) if (dep[Fa[i][x]] >= dep[y]) x = Fa[i][x];
if (x == y) return x;
Fordown(i, 18, 0) if (Fa[i][x] != Fa[i][y]) x = Fa[i][x], y = Fa[i][y];
return Fa[0][x];
}
int main()
{
#ifdef hany01
freopen("51nod1743.in", "r", stdin);
freopen("51nod1743.out", "w", stdout);
#endif
static int u, v, m, q, cnt;
n = read(), m = read(), q = read();
For(i, 1, n) W[i] = read();
For(i, 1, m) u = read(), v = read(), E[i] = (Edge){u, v, abs(W[u] - W[v])};
sort(E + 1, E + 1 + m), dsu.init();
For(i, 1, m) if (dsu.merge(E[i].u, E[i].v))
if (T[E[i].u].pb(E[i].v), T[E[i].v].pb(E[i].u), (cnt += use[i] = 1) == n - 1) break;
getDepth(1, 0);
For(i, 1, n) top[i] = i, rt[i] = i;
cur = n, dsu.init();
For(i, 1, m) if (!use[i]) {
for (u = dsu.find(E[i].u), v = dsu.find(E[i].v); u ^ v; u = dsu.find(u)) {
if (dep[u] < dep[v]) swap(u, v);
NT[++ cur].pb(rt[u]), NT[cur].pb(rt[dsu.find(fa[u])]);
dsu.merge(u, fa[u]), val[cur - n] = E[i].w, rt[dsu.find(u)] = cur;
}
}
Fordown(i, cur, 1) if (!vis[i])
++ clk, dep[i] = 1, DFS(i);
while (q --) {
u = read(), v = read();
if (vis[u] != vis[v]) { puts("infinitely"); continue; }
printf("%d\n", val[LCA(u, v) - n]);
}
return 0;
}