传送门
思路
kruskal 重构树的一个很好的应用
这道题中,我们建两棵重构树:
一棵按照边权为两点编号中的最小值,建一个小根堆重构树(称为树 a)
一棵按照边权为两点编号中的最大值,建一个大根堆重构树(称为树 b)
设 a 上叶子结点的 dfs 序为 da[u],b 上叶子结点的 dfs 序为 db[u]
在遍历树 b 到其叶子结点 u 时,我们就新建一棵权值主席树,让 da[u] 处加一
当询问 s,t,l,r 时,我们在树 a 从 s 向上跳到最浅的点 x 使 valx≥l,设 x 子树的 dfs 序区间为 al,ar
在再树 b 从 t 向上跳到最浅的点 y 使 valy≤r,设 y 子树的 dfs 序区间为 bl,br
最后我们询问 bl 到 br 的主席树中,区间 [al,ar] 的个数是否大于 0;如果是,代表可以从 s 到 t
这其实就是求:从 s 出发所能到的点集,与从 t 出发所能到的点集是否有交
代码
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define LL long long
#define FOR(i, x, y) for(int i = (x); i <= (y); i++)
#define ROF(i, x, y) for(int i = (x); i >= (y); i--)
#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)
inline int reads()
{
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
int n, m, q;
struct Node
{
int u, v, w;
}r[400005];
struct kruskal
{
int fa[200005], rt[400005], val[400005], pcnt;
std::vector<int> e[400005]; int st[400005][19];
int in[400005], out[400005], dcnt;
int find_fa(int x)
{
if(x == fa[x]) return x;
return fa[x] = find_fa(fa[x]);
}
int find_rt(int x)
{
if(x == rt[x]) return x;
return rt[x] = find_rt(rt[x]);
}
inline void Init(int i)
{
int x = find_fa(r[i].u), y = find_fa(r[i].v);
if(x == y) return;
fa[x] = y; x = find_rt(x), y = find_rt(y);
val[++pcnt] = r[i].w; rt[pcnt] = pcnt;
e[pcnt].emplace_back(x), e[pcnt].emplace_back(y);
rt[x] = rt[y] = pcnt;
}
}a, b;
void dfsa(int now)
{
if(now <= n) a.in[now] = a.out[now] = ++a.dcnt;
FOR(i, 1, 18)
{
int la = a.st[now][i - 1];
if(!a.st[la][i - 1]) break;
a.st[now][i] = a.st[la][i - 1];
}
for(int to : a.e[now])
{
a.st[to][0] = now;
dfsa(to);
if(!a.in[now]) a.in[now] = a.in[to];
a.out[now] = a.out[to];
}
}
namespace Seg
{
struct Tr
{
int sum, ls, rs;
}tr[6400005]; int cnt, rt[200005];
int modify(int pre, int l, int r, int to)
{
int now = ++cnt;
tr[now] = tr[pre];
if(l == r)
{
tr[now].sum++;
return now;
}
int mid = (l + r) >> 1;
if(to <= mid) tr[now].ls = modify(tr[pre].ls, l, mid, to);
else tr[now].rs = modify(tr[pre].rs, mid + 1, r, to);
tr[now].sum = tr[tr[now].ls].sum + tr[tr[now].rs].sum;
return now;
}
int query(int pre, int now, int l, int r, int L, int R)
{
if(L <= l && r <= R) return tr[now].sum - tr[pre].sum;
int mid = (l + r) >> 1, re = 0;
if(L <= mid) re += query(tr[pre].ls, tr[now].ls, l, mid, L, R);
if(mid < R) re += query(tr[pre].rs, tr[now].rs, mid + 1, r, L, R);
return re;
}
}
void dfsb(int now)
{
if(now <= n)
{
b.in[now] = b.out[now] = ++b.dcnt;
Seg::rt[b.dcnt] = Seg::modify(Seg::rt[b.dcnt - 1], 1, n, a.in[now]);
}
FOR(i, 1, 18)
{
int la = b.st[now][i - 1];
if(!b.st[la][i - 1]) break;
b.st[now][i] = b.st[la][i - 1];
}
for(int to : b.e[now])
{
b.st[to][0] = now;
dfsb(to);
if(!b.in[now]) b.in[now] = b.in[to];
b.out[now] = b.out[to];
}
}
inline void asolve(int u, int x, int &L, int &R)
{
ROF(i, 18, 0) if(a.st[u][i] && a.val[a.st[u][i]] >= x)
u = a.st[u][i];
L = a.in[u], R = a.out[u];
}
inline void bsolve(int u, int x, int &L, int &R)
{
ROF(i, 18, 0) if(b.st[u][i] && b.val[b.st[u][i]] <= x)
u = b.st[u][i];
L = b.in[u], R = b.out[u];
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif
n = reads(), m = reads(), q = reads();
FOR(i, 1, n) a.fa[i] = a.rt[i] = b.fa[i] = b.rt[i] = i;
a.pcnt = b.pcnt = n;
FOR(i, 1, m)
{
int u = reads() + 1, v = reads() + 1;
r[i] = (Node){u, v, std::min(u, v)};
}
std::sort(r + 1, r + 1 + m, [&](Node a, Node b){return a.w > b.w;});
FOR(i, 1, m) a.Init(i);
FOR(i, 1, m) r[i].w = std::max(r[i].u, r[i].v);
std::sort(r + 1, r + 1 + m, [&](Node a, Node b){return a.w < b.w;});
FOR(i, 1, m) b.Init(i);
dfsa(a.pcnt), dfsb(b.pcnt);
while(q--)
{
int s = reads() + 1, t = reads() + 1, l = reads() + 1, r = reads() + 1;
int al, ar, bl, br;
asolve(s, l, al, ar); bsolve(t, r, bl, br);
if(Seg::query(Seg::rt[bl - 1], Seg::rt[br], 1, n, al, ar))
puts("1");
else puts("0");
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!