P3247 [HNOI2016] 最小公倍数 题解
第一眼上去没什么明显的思路。图上问题一般没有什么好的多项式复杂度算法来解决。观察数据范围,注意到
现在考虑将它离线的具体方式:
注意到
现在分析复杂度。我们设块长为
代码:
#include <bits/stdc++.h>
#define N 100005
using namespace std;
int n, m;
struct DSU {
int fa[N], siz[N], mxa[N], mxb[N];
struct node {
int x, y, fx, fy, mxa, mxb, mya, myb;
};
node stk[N];
int top;
int fnd(int x) {
return x == fa[x] ? x : fnd(fa[x]);
}
void mge(int x, int y, int va, int vb) {
x = fnd(x), y = fnd(y);
if (siz[x] < siz[y]) swap(x, y);
stk[++top] = {x, y, fa[x], fa[y], mxa[x], mxb[x], mxa[y], mxb[y]};
fa[y] = x;
if (x != y) siz[x] += siz[y];
mxa[x] = max({mxa[x], mxa[y], va});
mxb[x] = max({mxb[x], mxb[y], vb});
}
void del(int t) {
while (1) {
node p = stk[top--];
int x = p.x, y = p.y;
if (x != y) siz[x] -= siz[y];
fa[x] = p.fx, fa[y] = p.fy;
mxa[x] = p.mxa, mxb[x] = p.mxb;
mxa[y] = p.mya, mxb[y] = p.myb;
if (top == t) return;
}
}
void init() {
for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1, mxa[i] = mxb[i] = -1;
top = 0;
}
} dsu;
struct node {
int x, y, a, b, id;
} e[N], q[N];
bool cmpa(node a, node b) {
return a.a < b.a;
}
bool cmpb(node a, node b) {
return a.b < b.b;
}
bool cmpe(int a, int b) {
return e[a].b < e[b].b;
}
bool cmpq(int a, int b) {
return q[a].b < q[b].b;
}
int B, bl[N], br[N], tot;
int ans[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
B = max((int)sqrt(m * log2(n)), 1), tot = m / B;
for (int i = 1; i <= tot; i++) bl[i] = br[i - 1] + 1, br[i] = bl[i] + B - 1;
if (br[tot] != m) {
++tot;
bl[tot] = br[tot - 1] + 1;
br[tot] = m;
}
for (int i = 1; i <= m; i++) cin >> e[i].x >> e[i].y >> e[i].a >> e[i].b;
sort(e + 1, e + 1 + m, cmpa);
int T;
cin >> T;
for (int i = 1; i <= T; i++) cin >> q[i].x >> q[i].y >> q[i].a >> q[i].b, q[i].id = i;
sort(q + 1, q + 1 + T, cmpb);
bl[tot + 1] = br[tot + 1] = N - 1;
e[N - 1] = {-1, -1, -1, -1};
for (int p = 1; p <= tot; p++) {
dsu.init();
vector<int>qu, egbf, egnw;
int la = e[bl[p]].a, ra = e[br[p]].a, lla = e[bl[p + 1]].a, rra = e[br[p + 1]].a;
for (int i = 1; i <= T; i++)
if ((la <= q[i].a && q[i].a <= ra) && !(lla <= q[i].a && q[i].a <= rra)) qu.push_back(i);
sort(qu.begin(), qu.end(), cmpq);
for (int i = 1; i < bl[p]; i++)
egbf.push_back(i);
for (int i = bl[p]; i <= br[p]; i++)
egnw.push_back(i);
sort(egbf.begin(), egbf.end(), cmpe);
sort(egnw.begin(), egnw.end(), cmpe);
int t = -1;
for (auto i : qu) {
while (t + 1 < (int)egbf.size() && q[i].b >= e[egbf[t + 1]].b) {
++t;
dsu.mge(e[egbf[t]].x, e[egbf[t]].y, e[egbf[t]].a, e[egbf[t]].b);
}
int nt = dsu.top;
for (auto j : egnw) {
if (q[i].a >= e[j].a && q[i].b >= e[j].b) dsu.mge(e[j].x, e[j].y, e[j].a, e[j].b);
}
int fx = dsu.fnd(q[i].x), fy = dsu.fnd(q[i].y);
if (fx == fy && q[i].a == dsu.mxa[fx] && q[i].b == dsu.mxb[fx])
ans[q[i].id] = 1;
if (dsu.top != nt) dsu.del(nt);
}
}
for (int i = 1; i <= T; i++) {
if (ans[i]) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现