【题目链接】
【思路要点】
- 首先对所有边按照\(A\)值排序,并分块。
- 对于每个块,我们处理\(A\)值在该块内的询问。
- 假设我们正在处理第\(i\)块,那么我们将第1到\(i-1\)块的边取出,并按\(B\)排序,然后按\(B\)从小到大的顺序处理本块内需要处理的询问。
- 当处理一个询问时,先加入\(B\)值比它小的边,用并查集维护联通性与联通块内\(A\)和\(B\)的最大值。
- 然后我们可能要额外加入第\(i\)块内的一些边,这时记录并查集被修改的位置,并在结束询问时还原并查集。
- 时间复杂度\(O(M*\sqrt{M}*LogM)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 100005; const int SIZE = 1500; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct edge {int x, y, a, b; }; struct info {int x, y, a, b, home; }; edge e[MAXN]; info a[MAXN]; int n, m, q; int tot, l[MAXN], r[MAXN], belong[MAXN]; int f[MAXN], Maxa[MAXN], Maxb[MAXN], size[MAXN]; int top, s[MAXN], sf[MAXN], sMaxa[MAXN], sMaxb[MAXN], ssize[MAXN]; bool ans[MAXN], instack[MAXN]; bool cmpea(edge x, edge y) {return x.a < y.a; } bool cmpia(info x, info y) {return x.a < y.a; } bool cmpeb(edge x, edge y) {return x.b < y.b; } bool cmpib(info x, info y) {return x.b < y.b; } int tmpfind(int x) { if (f[x] == x) return x; else return tmpfind(f[x]); } void tmpmerge(int x, int y, int a, int b) { int tx = tmpfind(x), ty = tmpfind(y); if (size[tx] < size[ty]) swap(tx, ty); if (!instack[tx]) { instack[tx] = true; s[++top] = tx; sf[tx] = f[tx]; sMaxa[tx] = Maxa[tx]; sMaxb[tx] = Maxb[tx]; ssize[tx] = size[tx]; } if (!instack[ty]) { instack[ty] = true; s[++top] = ty; sf[ty] = f[ty]; sMaxa[ty] = Maxa[ty]; sMaxb[ty] = Maxb[ty]; ssize[ty] = size[ty]; } f[ty] = tx; chkmax(Maxa[tx], a); chkmax(Maxa[tx], Maxa[ty]); chkmax(Maxb[tx], b); chkmax(Maxb[tx], Maxb[ty]); if (tx == ty) return; size[tx] += size[ty]; } int find(int x) { if (f[x] == x) return x; else return f[x] = find(f[x]); } void merge(int x, int y, int a, int b) { int tx = find(x), ty = find(y); if (size[tx] < size[ty]) swap(tx, ty); f[ty] = tx; chkmax(Maxa[tx], a); chkmax(Maxa[tx], Maxa[ty]); chkmax(Maxb[tx], b); chkmax(Maxb[tx], Maxb[ty]); if (tx == ty) return; size[tx] += size[ty]; } void restore() { while (top) { int tmp = s[top--]; instack[tmp] = false; f[tmp] = sf[tmp]; Maxa[tmp] = sMaxa[tmp]; Maxb[tmp] = sMaxb[tmp]; size[tmp] = ssize[tmp]; } } int main() { read(n), read(m); for (int i = 1; i <= m; i++) read(e[i].x), read(e[i].y), read(e[i].a), read(e[i].b); for (int i = 1; i <= m; i++) { if (i % SIZE == 1 % SIZE) l[++tot] = i; belong[i] = tot; r[tot] = i; } sort(e + 1, e + m + 1, cmpea); read(q); for (int i = 1; i <= q; i++) read(a[i].x), read(a[i].y), read(a[i].a), read(a[i].b), a[i].home = i; sort(a + 1, a + q + 1, cmpia); int last = 0; for (int p = 1; p <= tot; p++) { int end = last, val = e[r[p]].a; if (r[p] != m && e[r[p]].a == e[r[p] + 1].a) val--; while (end < q && a[end + 1].a <= val) end++; if (last == end) continue; sort(e + 1, e + l[p], cmpeb); sort(a + last + 1, a + end + 1, cmpib); for (int i = 1; i <= n; i++) { f[i] = i; Maxa[i] = -1; Maxb[i] = -1; size[i] = 1; } int now = 1; for (int i = last + 1; i <= end; i++) { while (now < l[p] && e[now].b <= a[i].b) { merge(e[now].x, e[now].y, e[now].a, e[now].b); now++; } for (int j = l[p]; j <= r[p]; j++) { if (e[j].a > a[i].a) break; if (e[j].b <= a[i].b) tmpmerge(e[j].x, e[j].y, e[j].a, e[j].b); } int tx = tmpfind(a[i].x), ty = tmpfind(a[i].y); if (tx == ty && Maxa[tx] == a[i].a && Maxb[tx] == a[i].b) ans[a[i].home] = true; restore(); } } for (int i = 1; i <= q; i++) if (ans[i]) printf("Yes\n"); else printf("No\n"); return 0; }