题目大意
B 国有 (n) 个城市, 一些城市间有若干条双向道路相连
每条道路有一个限制重量,大于该限制重量的车都不能通过
现在运输公司有 (q) 辆货车,每辆货车想从 (s_i) 市到 (t_i) 市,车的重量是 (w_i)
请问每一辆车是否能够到达目的地
Solution
Std
并查集在加边的时候从大到小加,并处理相关询问;
由于从大到小加,可以保证当前是最优的方案,直接处理。
实质也就是MST上的路径最值,不过离线下来,通过一个过程去实现,代码少。
My Solution
首先很明显求的是路径最小值最大。
而显而易见,最大生成树可以保证树上最小值尽可能大。
问题转换成求树上路径最小。
最大生成树 + 路径最小值(树链剖分 + ST表)实现,或树上倍增。
(mathrm{Code:})
#include <algorithm>
#include <climits>
#include <cstdio>
#include <iostream>
#define rint register int
#define FOR(i, a, b) for (rint i = (a); i <= (b); ++i)
#define S_H(T, i, u) for (rint i = T.fl[u]; i; i = T.net[i])
#define swap(x, y) (x ^= y ^= x ^= y)
const int N = 1e5 + 10, M = 3e5 + 10;
int n, m, Q;
int si[N], hs[N], f[N], d[N], a[N];
int top[N], tr[N], vs = 0, pr[N];
class Edge {
public:
int x, y, z;
} e[M << 1];
struct Tree {
int to[N << 1], net[N << 1], w[N << 1];
int fl[N], len, in[N];
inline void inc(int x, int y, int z) {
to[++len] = y;
w[len] = z;
++in[y];
net[len] = fl[x];
fl[x] = len;
}
} T;
struct US_find {
int f[N], n;
inline void Build(int _) {
n = _;
FOR(i, 1, n)
f[i] = i;
}
inline void Modify(int x, int y, int z) {
int u = Get(x), v = Get(y);
if (u != v) {
f[u] = v;
T.inc(x, y, z);
T.inc(y, x, z);
}
}
inline int Get(int x) { return x == f[x] ? x : f[x] = Get(f[x]); }
};
struct ST {
#define I(k) (1 << k)
int f[N][30], lg[N];
inline int Ask(int l, int r) {
int t = lg[r - l + 1];
return std ::min(f[l][t], f[r - I(t) + 1][t]);
}
inline void Work() {
lg[0] = -1;
FOR(i, 1, n)
lg[i] = lg[i >> 1] + 1;
FOR(i, 1, n)
f[i][0] = pr[i];
FOR(j, 1, 20)
FOR(i, 1, n - I(j) + 1)
f[i][j] = std ::min(f[i][j - 1], f[i + I(j - 1)][j - 1]);
}
} S;
//定义部分
inline int read() {
int s = 0, w = 1;
char c = getchar();
while ((c < '0' || c > '9') && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (c <= '9' && c >= '0')
s = (s << 1) + (s << 3) + c - '0', c = getchar();
return s * w;
}
template <class T>
inline void write(T x) {
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
return void();
}
void dfs(int u, int fa) {
si[u] = 1;
S_H(T, i, u) {
int v = T.to[i];
if (v == fa) continue;
f[v] = u, d[v] = d[u] + 1, a[v] = T.w[i];
dfs(v, u);
si[u] += si[v];
hs[u] = si[hs[u]] < si[v] ? v : hs[u];
}
}
void dfs_chain(int u, int k) {
top[pr[tr[u] = ++vs] = u] = k, pr[vs] = a[u];
if (!hs[u]) return void();
dfs_chain(hs[u], k);
S_H(T, i, u) {
int v = T.to[i];
if (v == f[u] || v == hs[u]) continue;
dfs_chain(v, v);
}
}
inline int Ask_chain(int x, int y) {
int minn = INT_MAX;
while (top[x] ^ top[y]) {
if (d[top[x]] < d[top[y]]) swap(x, y);
minn = std ::min(minn, S.Ask(tr[top[x]], tr[x]));
x = f[top[x]];
}
if (x == y) return minn;
if (d[x] < d[y]) swap(x, y);
minn = std ::min(minn, S.Ask(tr[y] + 1, tr[x]));
return minn;
}
//树链剖分操作
inline bool cmp(Edge x, Edge y) { return x.z > y.z; }
signed main(void) {
n = read(), m = read(), Q = read();
FOR(i, 1, m) {
int x = read(), y = read(), z = read();
e[i] = (Edge){x, y, z};
}
US_find F;
F.Build(n);
std ::sort(e + 1, e + m + 1, cmp);
FOR(i, 1, m) F.Modify(e[i].x, e[i].y, e[i].z);
//MST最大生成树
FOR(i, 1, n)
if (!si[i]) dfs(i, 0), dfs_chain(i, i);
//树剖预处理
S.Work();
FOR(i, 1, Q) {
int x = read(), y = read(), z = read();
if (F.Get(x) != F.Get(y)) {
puts("No");
continue;
}
//特判是否连通 !important;
int t = Ask_chain(x, y);
t >= z ? puts("Yes") : puts("No");
}
return 0;
}