【luogu P4899】werewolf 狼人(最小生成树)(主席树)

werewolf 狼人

题目链接:luogu P4899

题目大意

给你一个无向图,然后每次要从一个地方走到另外一个地方。
然后你在走的过程中要在一个点转换形态,转换之前你只能走大于等于 L 的点,转换之后你只能走小于等于 R 的点。
然后问你对于每次询问,要你回答能不能走。

思路

首先我们考虑把要走的路分成两段。
在转换之前走的,在转化之后走的。

那我们考虑这么搞,求出转换之前能到的,求出转化之后能从这个地方到终点的(由于是双向边,所以也是从终点能到的)。
然后如果这两个点集有交的话,我们就可以到。

那接着看如何搞,首先不难看出两段其实是同样的道理,你反过来一下就好了。
那就只看转换之前能到的。
那看到只能走大于等于的,那我们考虑这么搞。

用最小生成树的方法,从大到小枚举点,再枚举另一边比它大的边,然后建树,而且让小的作为父亲。
然后你就会发现,x 子树内的点,就是你保证走的点大于等于 x,而且在 x 出发能到的点。

然后你考虑在这道题里面,那你从 x 出发,然后要大于等于 l,那你就可以不断的从 x 往上跳,跳到不能跳,也就是如果跳了跳到的位置就 <l。然后再从那个位置的子树,就是你可以到的点了。

然后问题就变成两个树的两个子树,两个数的点有对应关系,问你这两个子树里面是否有一对对应的点。

那子树嘛,自然就想到是 dfs 序上的一段区间。

那我们可以搞个二维网格,如果一对是 (x,y),那这个位置就是 1
然后假设你两个数的两个 dfs 序上区间分别是 [x1,y1],[x2,y2],那就是求这个矩阵里面有没有 1

然后发现每个行或列只会有一个 1,所以我们考虑用主席树来搞。
然后就好啦。

代码

#include<cstdio> #include<algorithm> using namespace std; const int N = 200001; const int M = 400001; const int Q = 200001; struct node { int to, nxt; }e[M << 1]; int n, m, q, x, y, le[N], KK, l, r; struct ababtree { node ee[N]; int lee[N], KKK, fa[N][21], fath[N]; int dfn[N], tmp, st[N], ed[N], deg[N]; void clean() { for (int i = 1; i <= n; i++) fath[i] = i; } int find(int now) { if (fath[now] == now) return now; return fath[now] = find(fath[now]); } void add(int x, int y) { ee[++KKK] = (node){y, lee[x]}; lee[x] = KKK; } void build(bool op) {//搞最小生成树 int kn = 0; if (!op) { for (int i = n; i >= 1; i--) { for (int j = le[i]; j; j = e[j].nxt) if (e[j].to > i) { int x = find(i), y = find(e[j].to); if (x != y) { fath[y] = x; add(x, y); kn++; if (kn == n - 1) return ; } } } } else { for (int i = 1; i <= n; i++) { for (int j = le[i]; j; j = e[j].nxt) if (e[j].to < i) { int x = find(i), y = find(e[j].to); if (x != y) { fath[y] = x; add(x, y); kn++; if (kn == n - 1) return ; } } } } } void dfs(int now, int father) { st[now] = ++tmp; dfn[tmp] = now; fa[now][0] = father; deg[now] = deg[father] + 1; for (int i = lee[now]; i; i = ee[i].nxt) dfs(ee[i].to, now); ed[now] = tmp; } void bz() { for (int i = 1; i <= 20; i++) for (int j = 1; j <= n; j++) fa[j][i] = fa[fa[j][i - 1]][i - 1]; } int jmp(int x, int y, bool op) {//跳到临界点 if (!op) { for (int i = 20; i >= 0; i--) if (fa[x][i] >= y) x = fa[x][i]; } else { for (int i = 20; i >= 0; i--) if (fa[x][i] && fa[x][i] <= y) x = fa[x][i]; } return x; } }A, B; struct zxtree {//主席树 int ls[N << 6], rs[N << 6], val[N << 6], tot; int copy(int x) { int y = ++tot; ls[y] = ls[x]; rs[y] = rs[x]; val[y] = val[x]; return y; } void up(int now) { val[now] = val[ls[now]] + val[rs[now]]; } int insert(int now, int l, int r, int pl, int va) { now = copy(now); if (l == r) { val[now] += va; return now; } int mid = (l + r) >> 1; if (pl <= mid) ls[now] = insert(ls[now], l, mid, pl, va); else rs[now] = insert(rs[now], mid + 1, r, pl, va); up(now); return now; } int query(int now, int l, int r, int L, int R) { if (!now) return 0; if (L <= l && r <= R) return val[now]; int mid = (l + r) >> 1, re = 0; if (L <= mid) re += query(ls[now], l, mid, L, R); if (mid < R) re += query(rs[now], mid + 1, r, L, R); return re; } }T; int rt[N]; void add(int x, int y) { e[++KK] = (node){y, le[x]}; le[x] = KK; e[++KK] = (node){x, le[y]}; le[y] = KK; } int main() { scanf("%d %d %d", &n, &m, &q); for (int i = 1; i <= m; i++) { scanf("%d %d", &x, &y); x++; y++; add(x, y); } A.clean(); B.clean(); A.build(0); B.build(1); A.dfs(1, 0); B.dfs(n, 0); A.bz(); B.bz(); for (int i = 1; i <= n; i++) {//对应的位置 rt[i] = T.insert(rt[i - 1], 1, n, B.st[A.dfn[i]], 1); } while(q--) { scanf("%d %d %d %d", &x, &y, &l, &r); x++; y++; l++; r++; l = A.jmp(x, l, 0); r = B.jmp(y, r, 1); if (T.query(rt[A.ed[l]], 1, n, B.st[r], B.ed[r]) - T.query(rt[A.st[l] - 1], 1, n, B.st[r], B.ed[r])) printf("1\n"); else printf("0\n"); } return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P4899.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(49)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示