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

news/2024/10/10 10:25:01

Problem Link

思考 Tom 怎么获胜,有以下两种情况:

  1. Tom 不断限制 Jerry 的活动范围,直到困死。
  2. ~Tom 瞎走都可以赢~,有一个点能让 Tom 必胜。

对于(1),显然 Tom 需要不断走割点,由此想到圆方树。

这里有个圆方树

假设 Tom 在 \(a\),Jerry 在 \(d\),Jerry 能在 \(a\) 的子树里任意走,所以 Tom 需要让 \(a\) 能直接到达 \(b\)\(c\),否则就输了。由此看出每当 Tom 在 \(x\),Jerry 在 \(x\) 的子树 \(y\) 内时,\(x\) 必须直接到达 \(y\) 代表的点双连通分量中的任意点。此时 Tom 必胜。

对于(2),考虑能让 Tom 必胜的那个点 \(x\),此时 Jerry 可以在任何地方(否则(1)就讨论过了)。Tom 必胜条件就是对于 \(x\) 的任何子树,(1)的条件都成立。

若(1)(2)都不成立,Tom 必败。

接下来实现挺复杂的,我看其他 dalao 题解是没怎么看懂(我太蒻了),这里介绍一下我的写法。

考虑如何表示 \(x\) 能直接到达其点双连通分量的任意点。可以将这个状态放到 \(x\) 到对应方点的边上。

枚举原图上的边,如 \((a,b)\),则在圆方树上让 \(w(a,A)\)\(w(b,A)\) 各加一,这很好实现。\(a\) 能直接到 \(A\) 中任意点的充要条件是 \(w(a,A) = sz_A-1\)\(sz_A\)\(A\) 代表的点双连通分量的大小)。

必胜条件可以转化为:对于一个根为 \(x\) 的子树中,所有 \(u\) 是圆点,\(v\) 是方点,\(dep_u<dep_v\) 的边 \((u,v)\) (如下图红边)均合法。记不合法的边的数量\(f_x\),满足条件且不合法的的边称为不合法边。

容易得到转移:\(f_{y \in son_x} \rightarrow f_x\)。对于不合法边 \((u,v)\),为代码更好写,让 \(f_v \leftarrow f_v+1\)

考虑换根 dp,记 \(g_x\) 为删去 \(x\) 的子树(除了 \(x\))剩下的子树中不合法边的数量

转移为:\(g_y=g_x+f_x-f_y+\Delta\)

\(\Delta\) 的取值有:

  • \((x,y)\) 有原来是不合法边,\(\Delta=-1\)
  • \((x,y)\) 现在是不合法边,\(\Delta=1\)
  • \((x,y)\) 啥都不是,\(\Delta=0\)

最后用 lca 求出需要满足的子树 \(x\),注意特判情况(2)。

默认 \(n,m,q\) 同级,时间复杂度为 \(O(n\log n)\)

update on 2024.10.3 修改代码中的部分错误

Code:

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cassert>
#include<vector>
#include<cmath>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10, M = 2 * N;
int dfn[N], low[N], st[N], sz[N], f[N], g[N], tot;
int fa[N][21], dep[N], n, m, q, ifa[N];
vector <int> e[N];
int head[N], vi[M], ne[M], wi[M], htot;
vector < pair <int, int> > vt;
void addedge(int u, int v){ne[++htot] = head[u], vi[htot] = v, head[u] = htot;
}
void add(int u, int v){addedge(u, v);addedge(v, u);
}
void tarjin(int x){dfn[x] = low[x] = ++dfn[0], st[++st[0]] = x;for(int y : e[x]){if(!dfn[y]){tarjin(y);low[x] = min(low[x], low[y]);if(low[y] == dfn[x]){add(x, ++tot);sz[tot] = 2;while(st[st[0]] != y){sz[tot]++;add(st[st[0]--], tot);}add(st[st[0]--], tot);}}elselow[x] = min(low[x], dfn[y]);}
}
void ad(int u, int v){while(u != v){if(dep[u] < dep[v])swap(u, v);wi[ifa[u]]++, u = fa[u][0];}
}
void dfs1(int x, int pfa){dep[x] = dep[pfa] + 1, fa[x][0] = pfa;for(int i = 1; i <= 20; i++)fa[x][i] = fa[fa[x][i - 1]][i - 1];for(int i = head[x]; i; i = ne[i]){int y = vi[i];if(y == pfa)continue;ifa[y] = i;dfs1(y, x);}
}
void dfs2(int x, int pfa, int op){f[x] = op;for(int i = head[x]; i; i = ne[i]){int y = vi[i];if(y == pfa)continue;dfs2(y, x, (x <= n && wi[i] != sz[y] - 1));f[x] += f[y];}
}
void dfs3(int x, int pfa){for(int i = head[x]; i; i = ne[i]){int y = vi[i];if(y == pfa)continue;int t = g[x] + f[x] - f[y];if(y <= n && wi[i] != sz[x] - 1)t++;if(x <= n && wi[i] != sz[y] - 1)t--;g[y] = t;dfs3(y, x);}
}
int lca(int x, int y){if(dep[x] < dep[y])swap(x, y);for(int i = 20; ~i; i--)if(dep[fa[x][i]] >= dep[y])x = fa[x][i];if(x == y)return x;for(int i = 20; ~i; i--)if(fa[x][i] != fa[y][i])x = fa[x][i], y = fa[y][i];return fa[x][0];
}
bool check(int x, int y){if(lca(x, y) == x){int z = y;for(int i = 20; ~i; i--)if(dep[fa[z][i]] > dep[x])z = fa[z][i];return f[z] == 0;}return g[x] == 0;
}
int main(){ios::sync_with_stdio(false);cin.tie(nullptr);cin >> n >> m >> q;for(int i = 1, u, v; i <= m; i++){cin >> u >> v;vt.push_back(make_pair(u, v));e[u].push_back(v);e[v].push_back(u);}tot = n;tarjin(1);dfs1(1, 0);for(auto i : vt)ad(i.first, i.second);dfs2(1, 0, 0);dfs3(1, 0);bool flag = 0;for(int i = 1; i <= n; i++)flag |= (f[i] + g[i] == 0);while(q--){int a, b;cin >> a >> b;if(flag){cout << "Yes\n";continue;}cout << (check(a, b)? "Yes\n" : "No\n");}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

利用大模型设计测试用例

安装python 依赖 pip install torch transformers accelerate sentencepiece python代码,设计一个测试用例from transformers import AutoTokenizer, AutoModelForCausalLM import os import torch # 导入 torch 库# 设置 HTTP 和 HTTPS 代理(如果需要) os.environ[http_pr…

测试流程必须严格执行吗?

技术交流群有同学问了这样一个问题:公司有较为严格的测试流程和项目交付规范,但目前工期紧张且资源严重不足,是否还需要严格遵守流程规范。如果严格遵守流程规范则可能要延期交付,或者项目组的同学需要大量加班,有什么解决办法?该说不说,这确实是很头疼的问题。对项目管…

Semaphore源码简单解读

Semaphore源码解读 注意,阅读本文需要了解AQS,AQS采用了模板设计模式。后续本人会完善这篇文章 Semaphore的方法acquire() 阻塞获得一个许可,会阻塞,直到得到一个可用许可或被中断 重载版本 acquire(n) :尝试获取n个许可 acquireUninterruptibly() 类acquire,但不可中断 …

捕鱼船识别检测预警系统

捕鱼船识别检测预警系统通过图像识别和数据分析技术,捕鱼船识别检测预警系统实时监测水域中的捕鱼船活动,系统利用河道两岸的摄像头,对捕鱼船的外形、大小、航行轨迹等进行检测和识别。捕鱼船识别检测预警系统一旦系统识别到违规捕捞行为,立即发出预警信号,并通知相关部门…

加油站抽烟烟火智能识别系统

加油站抽烟烟火智能识别系统利用摄像头和智能分析技术,加油站抽烟烟火智能识别系统实时监测加油站内的加油人员行为,加油站抽烟烟火智能识别系统通过图像识别和行为分析,识别出抽烟和燃放烟火的情况,并发出预警信号以提醒相关人员。加油站抽烟烟火智能识别系统能够实时监测…

希音面试:Redis脑裂,如何预防?你能解决吗?(看这篇就够了)

文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :《尼恩Java面试宝典》 持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备 免费赠送 :《尼恩技术圣经+高并发系列PDF》 ,帮你 实现技术自由,…

稀疏促进动态模态分解(SPDMD)详细介绍以及应用

在数据驱动分析领域,从复杂流体流动中提取有意义的模式一直是一个重大挑战。稀疏促进动态模态分解(Sparsity Promoting Dynamic Mode Decomposition, SPDMD)提供了一种有效方法,能够揭示最主要的特征,同时去除冗余信息,从而实现更高效和更具洞察力的分解。这种方法将动态…