题解 P7353【[2020-2021 集训队作业] Tom Jerry】

news/2025/3/20 11:10:10/文章来源:https://www.cnblogs.com/caijianhong/p/18782667

题解 P7353【[2020-2021 集训队作业] Tom & Jerry】

题目描述

给定一张包含 \(n\) 个顶点和 \(m\) 条边的 无向连通图,Tom 和 Jerry 在图上进行了 \(q\) 次追逐游戏。

在第 \(i\) 次游戏中,Tom 一开始位于顶点 \(a_i\),而 Jerry 一开始位于顶点 \(b_i\)(双方任何时候都知道自己和对方的位置),追逐规则如下:

  • Jerry 和 Tom 交替行动,Jerry 先行动。

  • Jerry 每次行动可以通过无向图中的 任意多条边(可以选择不移动),但是在移动过程中不能经过 Tom 当前所在的结点,否则就会被抓住。

  • Tom 每次行动只能通过无向图中的 至多一条边(可以选择不移动)。

  • 如果 Tom 在一次行动后到达了 Jerry 的位置,那么 Tom 胜利。

Tom 尽量想要胜利,而 Jerry 会尽量阻止 Tom 胜利。

现在你需要对于每一局游戏,求出 Tom 是否一定能在有限次行动内获胜。

对于 \(100\%\) 的数据,\(1\leq n,m,q\leq 10^5\)\(1\leq x,y,a,b\leq n\)\(a_i\ne b_i\)

保证给出的无向图连通,且不含重边和自环。

solution

由于要求 Jerry 的路径不能与 Tom 的位置重叠,这里就蕴含了一种割点的想法,考虑建圆方树。

首先可以发现,如果一个圆点能一步到达它相邻某个方点的点双中所有点,Tom 一旦站上去这个点,如果 Jerry 逃不出这个点双,Jerry 就会被吃;如果没有这样的点,Jerry 一直待在这个点双里,Jerry 就赢了。可以发现这种点异常的关键,不如先取个名字,叫作一步杀点。

假如说 Jerry 待在一个点双里面,Tom 来的方向到达这个点双的第一个点无法一步杀,Jerry 要躲在 Tom 到的第一个点一步到不了的点。当 Tom 进入这个点双的时候,Jerry 就可以开始考虑他应该逃向何处。可以发现 Jerry 实际上整张图都可以去,分两种情况,如果要经过 Tom 所在的点,那么让 Tom 先走一步,然后 Jerry 逃走;如果不经过 Tom 所在点,Jerry 直接跑就可以了。

但是一直跑下去也不是一个办法,我们需要找一种稳定的策略。可以发现核心就在于 Tom 来的方向到达这个点双的第一个点无法一步杀,假如我们找到两个点双,假如它们对应的方点 \(x, y\) 之间的路径 \(x- u- \cdots- v- y\) 上,\(u\) 无法一步杀 \(x\)\(v\) 无法一步杀 \(y\),那么 Jerry 在这两个点双之间来回奔跑就行了。只要一开始 Jerry 到达这对点双的一端,Jerry 就赢了。


总结:如果一个圆点不能一步到达它相邻某个方点的点双中所有点,那么将这条边定向为圆点到方点。我们仔细分讨一下,就会发现:

  1. 如果有两个方点 \(x, y\),它们之间的路径形如 \(x- u- \cdots- v- y\),如果发现 \(u\to x\)\(v\to y\) 这两条边被定向了,那么标记 \((x, y)\) 为好的点对。询问 \(a, b\) 时,删去 \(a\),若有一个好的点对的其中一端在 \(b\) 所在连通块中,那么 Jerry 就获胜了(Jerry 可以在这两个方点中来回横跳)。
  2. 还有一种情况,如果一个方点上没有点定向到它,而同时 Jerry 一开始可以到达这个方点,那么 Jerry 也获胜了。

可以证明这个和 ix35 的结论是等价的,过程就不写了。至此可以平方完成,然后就用其它技术例如树上倍增之类的优化一下就可以了,后面的部分一点都不难,就不写了。

code

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
constexpr int N = 1e5 + 10;
int n, m, q, siz[N << 1];
bool upw[N << 1];
basic_string<int> g[N], tr[N << 1];
vector<pair<int, int>> E[N << 1];
int dfn[N << 1], tot, cnt;
void tarjan(int u) {/*{{{*/static int low[N], stk[N], top;static vector<pair<int, int>> Estk;low[u] = dfn[u] = ++cnt, stk[++top] = u;for (int v : g[u]) {auto e = make_pair(u, v);if (dfn[v]) {low[u] = min(low[u], dfn[v]);if (dfn[v] < dfn[u]) Estk.push_back(e);} else {Estk.push_back(e);tarjan(v), low[u] = min(low[u], low[v]);if (low[v] >= dfn[u]) {int p = ++tot;tr[p] += u, tr[u] += p;do tr[p] += stk[top], tr[stk[top]] += p; while (stk[top--] != v);auto lst = e;do E[p].push_back(lst = Estk.back()), Estk.pop_back(); while (lst != e);}}}
}/*}}}*/
auto getw(int u, int v) { return dfn[u] < dfn[v] ? upw[v] : upw[u]; }
int anc[18][N << 1], dep[N << 1];
void dfs1(int u, int fa) {anc[0][u] = fa;dfn[u] = ++cnt, siz[u] = 1, dep[u] = dep[fa] + 1;if (u > n) {auto bg = E[u].begin(), ed = E[u].end();for (auto& [x, y] : E[u]) if (x > y) swap(x, y);sort(bg, ed), E[u].erase(unique(bg, ed), ed);static int deg[N << 1];for (int v : tr[u]) deg[v] = 0;for (auto [x, y] : E[u]) deg[x] += 1, deg[y] += 1;for (int v : tr[u]) if (deg[v] != (int)tr[u].size() - 1) upw[v == fa ? u : v] = true;}for (int v : tr[u]) if (v != fa) dfs1(v, u), siz[u] += siz[v];
}
bool ok[N << 1];
vector<int> dfs2(int u, int fa) {bool done = true;vector<int> pre;for (int v : tr[u]) if (v != fa) {auto&& res = dfs2(v, u);if (v > n && getw(u, v)) res.push_back(v);if (!res.empty()) {if (done || !pre.empty()) {done = true;for (int x : pre) ok[x] = true;for (int x : res) ok[x] = true;pre.clear();}}}return pre;
}
int jump(int u, int k) {for (int j = 17; j >= 0; j--) if (k >> j & 1) u = anc[j][u];return u;
}
vector<int> vec;
bool cok(int l, int r) {auto it = lower_bound(vec.begin(), vec.end(), l);return it != vec.end() && *it <= r;
}
bool check(int x, int y) {if (dfn[x] <= dfn[y] && dfn[y] < dfn[x] + siz[x]) {y = jump(y, dep[y] - dep[x] - 1);return cok(dfn[y], dfn[y] + siz[y] - 1);} else {return cok(1, dfn[x] - 1) || cok(dfn[x] + siz[x], tot);}
}
int main() {
#ifndef LOCALcin.tie(nullptr)->sync_with_stdio(false);
#endifcin >> n >> m >> q, tot = n;for (int i = 1, u, v; i <= m; i++) cin >> u >> v, g[u] += v, g[v] += u;for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i);cnt = 0, dfs1(1, 0);for (int i = n + 1; i <= tot; i++) {int cc = 0;for (int v : tr[i]) if (getw(i, v)) ++cc;if (cc == (int)tr[i].size()) ok[i] = true;}dfs2(1, 0);for (int i = 1; i <= tot; i++) if (ok[i]) vec.push_back(dfn[i]);sort(vec.begin(), vec.end());for (int j = 1; j <= 17; j++) {for (int i = 1; i <= tot; i++) anc[j][i] = anc[j - 1][anc[j - 1][i]];}while (q--) {int x, y;cin >> x >> y;cout << (!check(x, y) ? "Yes" : "No") << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/901931.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

五分钟带你看懂 NVIDIA 和 AI 的未来

(配图:Photo by BoliviaInteligente on Unsplash)前言:2025 年 3 月 18 日,在美国加州圣何塞举行的 GTC 2025 大会上,NVIDIA CEO 黄仁勋发表了长达两小时的主题演讲,详细介绍了 NVIDIA 的未来路线图。 这场被誉为“AI 超级碗”的盛会,吸引了全球开发者、创新者和行业领导…

初识 WebSocket 协议

什么是 WebSocket WebSocket 是一种网络通信协议,是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 属于应用层协议,它基于 TCP 传输协议,并复用 HTTP 的握手通道。 为什么出现 WebSocket 我们已经拥有了 HTTP 协议,为什么还要搞出一套 WebSocket…

易基因:WGBS+ChIP-seq技术揭示Cdx2转录因子在发育与稳态中的动态结合机制|NC/IF14.7

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 Cdx2是一个关键的转录因子,在小鼠肠道上皮细胞的发育过程中起着决定性的作用。它在胚胎期和成年期的肠道上皮细胞中都有表达,但其结合的基因组位点在发育和成年期有所不同。DNA甲基化是一种表观遗传修饰,通…

FALL

FALL 信息收集 扫描目标主机ip ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:84:b2:cc, IPv4: 192.168.158.143 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.158.1 00:50:56:c0:0…

信创龙头股在政策支持下的投资机会解读

信创产业,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。近年来,随着政策的大力支持,信创产业发展势头迅猛,信创龙头股也备受投资者关注。在政策东风的助力下,信创龙头股蕴含着丰富的投资机会,值得深入剖析。 政策支…

通过 INFINI Console 集中管理极限网关配置

之前有做过介绍实现极限网关(INFINI Gateway) 配置动态加载,这是一个 Gateway 实例的操作,直接在服务器上修改配置文件。如果有多个 Gateway 实例需要调整,登录多台主机修改配置文件就有些繁琐,有没有简便的方法呢? 答案是: 当然有! INFINI Gateway 有配套的管理页面,…

如何精准控制生产成本?8年生产主管告诉我掌握这些底层逻辑!

你是不是常常听到“控制成本”这个词,但却搞不清楚到底应该从哪里入手? 其实,成本控制并不是简单的削减支出,而是要在每个环节上做到精益求精。 作为一名有8年经验的生产主管,我可以告诉你,成本控制的关键在于对生产过程中的每一环节都要有清晰的了解和精准的把控。下文介…

CIMCO Edit 2024软件下载与安装教程

CIMCO Edit 2024是Cimco Integration公司推出的一款强大的数控程序编辑器,可帮助用户进行存储和检索NC程序、NC程序优化、后处理、以及快速NC程序仿真,它拥有强大而实用的数控编辑功能、文件的智能比较、刀位轨迹的三维模拟、DNC传输等强大功能,可帮助用户更快捷的完成NC程序…

FunASR: 让AI听懂你的声音

分享一个语音识别黑科技——开源免费的FunASR!我们先看下Funasr的语音识别效果。第一个是识别MP4视频文件。第二个是,电话语音实时识别。FunASR有两个识别引擎,离线识别 和 实时识别。 离线识别引擎,主要用途是对录音文件进行转写,得到文本结果。 典型的使用场景:会议录音…

启航杯writeup

启航杯writeup 一、web 1.Easy_include题解打开网址得到php代码,发现存在可以通过伪协议来绕过过滤​ 2.构造伪协议 ​ 命令会反向输出所有以fl开头的文件内容输出得到的内容。 ?file=data://text/plain,<?=system(tac fl*);?>​ 3.得到flag2.PCR(文件上传请求)…

使用ArgoCD管理Kubernetes部署指南

对于寻求利用云原生技术力量的组织来说,高效管理 Kubernetes 部署至关重要。ArgoCD 是一款针对 Kubernetes 的声明式 GitOps 持续交付工具,它是一种强大的解决方案。它有助于根据存储在 Git 存储库中的配置自动部署应用程序,从而使 Kubernetes 集群中的应用程序状态与 Git 中…

DeepC2—基于DeepSeek的C2平台

蹭个DeepSeek热点最近DeepSeek很火,蹭个热点,前几天搞了个自动生成工具的网站,有模有样吧,作用的话看看就行,网上绝大部分所谓的Agent也就这样...