题目
Luogu
LOJ
Acinwg
思路
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 100010, M = 50010;
int n, m, q, L[N], R[N], ans[N];
struct EDGE { int u, v, a, b; } E[N];
bool cmp1(EDGE a, EDGE b) { return a.a < b.a; }
bool cmp2(EDGE a, EDGE b) { return a.b < b.b; }
struct QUERY { int u, v, a, b, id; } Q[N];
bool cmp3(QUERY a, QUERY b) { return a.b < b.b; }
vector<int> T[1000];
int p[N], dep[N], MA[N], MB[N], top;
int find(int x) { return x == p[x] ? x : find(p[x]); }
struct OPER { int u, v, a, b, d; } stk[N];
void merge(int u, int v, int a, int b) {
u = find(u), v = find(v);
if (dep[u] < dep[v]) swap(u, v);
stk[++top] = (OPER){ u, v, MA[u], MB[u], dep[u] };
MA[u] = max(MA[u], a), MB[u] = max(MB[u], b);
if (u == v) return;
p[v] = u, dep[u] = max(dep[u], dep[v] + 1);
MA[u] = max(MA[u], MA[v]), MB[u] = max(MB[u], MB[v]);
}
void remove(int x) {
int u = stk[x].u, v = stk[x].v;
p[v] = v, dep[u] = stk[x].d;
MA[u] = stk[x].a, MB[u] = stk[x].b;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++)
cin >> E[i].u >> E[i].v >> E[i].a >> E[i].b;
cin >> q;
for (int i = 1; i <= q; i++)
cin >> Q[i].u >> Q[i].v >> Q[i].a >> Q[i].b, Q[i].id = i;
sort(E + 1, E + m + 1, cmp1);
sort(Q + 1, Q + q + 1, cmp3);
int B = sqrt(m * log2(n)), S = (m + B - 1) / B;
for (int i = 1; i <= S; i++)
L[i] = (i - 1) * B + 1, R[i] = min(m, i * B);
for (int i = 1, j; j = 0, i <= q; i++) {
while (j < S && Q[i].a >= E[R[j]].a) j++;
T[j].push_back(i);
}
for (int k = 1; k <= S; k++) {
// 排序外加初始化
sort(E + 1, E + R[k - 1] + 1, cmp2);
for (int i = 1; i <= n; i++)
p[i] = i, dep[i] = 0, MA[i] = MB[i] = -1;
for (int i = 0, j = 1; i < T[k].size(); i++) {
QUERY t = Q[T[k][i]];
// 找一下之前的块是否可以加边
while (j < L[k] && E[j].b <= t.b)
merge(E[j].u, E[j].v, E[j].a, E[j].b), j++;
top = 0; // top重置一下, 因为之后加的边要撤销
// 暴力找当前块, 是否有满足条件的
for (int u = L[k]; u <= R[k]; u++)
if (E[u].a <= t.a && E[u].b <= t.b)
merge(E[u].u, E[u].v, E[u].a, E[u].b);
int x = find(t.u), y = find(t.v);
// 如果两点联通, 且路径上最大的 A, B 符合要求
ans[t.id] = (x == y && MA[x] == t.a && MB[x] == t.b);
// 删除当前块加的边
while (top) remove(top--);
}
}
for (int i = 1; i <= q; i++)
cout << (ans[i] ? "Yes" : "No") << endl;
return 0;
}