P4899 [IOI2018] werewolf 狼人

传送门


思路

kruskal 重构树的一个很好的应用

这道题中,我们建两棵重构树:

一棵按照边权为两点编号中的最值,建一个根堆重构树(称为树 a

一棵按照边权为两点编号中的最值,建一个根堆重构树(称为树 b

a 上叶子结点的 dfs 序为 da[u]b 上叶子结点的 dfs 序为 db[u]

在遍历树 b 到其叶子结点 u 时,我们就新建一棵权值主席树,让 da[u] 处加一

当询问 s,t,l,r 时,我们在树 as 向上跳到最浅的点 x 使 valxl,设 x 子树的 dfs 序区间为 al,ar

在再树 bt 向上跳到最浅的点 y 使 valyr,设 y 子树的 dfs 序区间为 bl,br

最后我们询问 blbr 的主席树中,区间 [al,ar] 的个数是否大于 0;如果是,代表可以从 st

这其实就是求:从 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__

本文作者zuytong
本文链接https://www.cnblogs.com/zuytong/p/16694362.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zuytong  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示