[APIO2022] 游戏 题解
Description
传送门
Solution
注意到,原问题等价于加边,查询是否存在一个包含前 k k k 个点至少一者(令其为关键点)的环,并强制在线。
算法一
令 L u L_u Lu 表示节点 u u u 可达的编号最大的关键点, R u R_u Ru 表示可达节点 u u u 的编号最小的关键点。那么,答案为 1 1 1 当且仅当存在 u u u 使 L u ≥ R u L_u \ge R_u Lu≥Ru。
每当加入一条边 ( u , v ) (u,v) (u,v) 后,我们从 u u u 出发往外 dfs,不断尝试用 R u R_u Ru 来更新其他的 R R R;同理,我们也从 v v v 在反图上往外 dfs,不断尝试用 L v L_v Lv 来更新其他的 L L L。
一般实现的复杂度是 O ( m ( n + m ) ) O(m(n+m)) O(m(n+m)) 的,但如果我们加一个剪枝:无法更新就返回,那么每走一条边就会使一个节点的 L , R L,R L,R 之一产生变化。而根据势能分析,每个节点的 L , R L,R L,R 的变化次数总和是 O ( n k ) O(nk) O(nk) 的,所以总复杂度其实是 O ( ( n + m ) k ) O((n+m)k) O((n+m)k) 的。
期望得分 60 60 60 分。
算法二
既然关键点数量不多时算法一优秀,那么我们考虑将关键点变少。具体来说,我们分块,对于每个节点 u u u 维护 L u , R u L_u,R_u Lu,Ru 所在的块。当块长为 k \sqrt k k 时,复杂度就是 O ( ( n + m ) k ) O((n+m) \sqrt k) O((n+m)k ) 的。
特别的,若 L u , R u L_u,R_u Lu,Ru 属于同一个块,那么暴力更新。由于块长不大,所以这一部分的复杂度也是 O ( ( n + m ) k ) O((n+m) \sqrt k) O((n+m)k ) 的。
总时间复杂度 O ( ( n + m ) k ) O((n+m) \sqrt k) O((n+m)k ),期望得分 [ 60 , 100 ] [60,100] [60,100] 分。
算法三
首先你要注意到,分块本质上就是线段树的退化版,将线段树的层数压缩到了 2 2 2。然而,本题并不需要依赖分块的特殊结构,于是我们考虑转而用线段树来维护。
具体来说,以 [ − 1 , k ] [-1,k] [−1,k] 为值域建立线段树,将每个点 u u u 记录在极小的包含 [ L u , R u ] [L_u,R_u] [Lu,Ru] 的线段树节点处。我们不断地尝试用下层更新上层的点,使各个节点被记录的位置不断变深。在实现方面,我们并不需要建立线段树,只需对各个 u u u 维护其在虚拟的线段树上对应的区间即可。
由于线段树只有 O ( log k ) O(\log k) O(logk) 层,所以总复杂度 O ( ( n + m ) log k ) O((n+m) \log k) O((n+m)logk),完美解决本题。
Summary
看到本题,非常容易想到维护 L , R L,R L,R。
首先考虑 60 60 60 分怎么做,根据势能分析,发现 dfs 一下的复杂度就是对的。
再考虑 100 100 100 分怎么做。由于关键点的数量较少可以做,那么我们可以分块,这样就能做到较为优秀的 O ( ( n + m ) k ) O((n+m) \sqrt k) O((n+m)k )。
最后发现做法并不依赖分块结构的特殊性,于是转而用线段树大力维护,就能做到完美的 O ( ( n + m ) log k ) O((n+m) \log k) O((n+m)logk) 了。
本题关键在于挖掘出转移的特殊性,并考察了对分块,分治等结构的清楚认识,是一道不可多得的好题。
Code
略微压行,代码很短,只有 663 B。
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;int n,k,l[N],r[N]; vector<int> A[N],B[N];
void init(int _n,int _k){n=_n,k=_k;for (int i=0;i<k;i++) l[i]=r[i]=i;for (int i=k;i<n;i++) l[i]=-1,r[i]=k;
}
bool upd(int u);
bool chk(int u,int v){if (l[u]>=r[v]) return 1;int midu=(l[u]+r[u])>>1,midv=(l[v]+r[v])>>1;if (l[u]>midv) return l[v]=midv+1,upd(v);if (r[v]<=midu) return r[u]=midu,upd(u);return 0;
}
bool upd(int u){for (auto v:A[u]) {if(chk(u,v))return 1;}for (auto v:B[u]) {if(chk(v,u))return 1;}return 0;
}
int add_teleporter(int u,int v){A[u].push_back(v),B[v].push_back(u);return chk(u,v);}
[APIO2022] 游戏 题解相关推荐
- 阿狸和桃子的游戏题解
阿狸和桃子的游戏题解 每一道代码简单的黑题都有着诡异的思想,真不知道出题者怎么想的. 而这道题的重点在于把边权转换为点权, 此题的方式是将边权w平均分给被连接的两点u和v. 若u和v都被一人选择,则他 ...
- 洛谷P1129 [ZJOI2007] 矩阵游戏 题解
洛谷P1129 [ZJOI2007] 矩阵游戏 题解 题目链接:P1129 [ZJOI2007] 矩阵游戏 题意:给定一张有黑白棋子的正方形棋盘,问存不存在解法使得经过若干次交换行或列的操作后,左上角 ...
- P1199(NOIP2010 普及组)三国游戏 题解
P1199(NOIP2010 普及组)三国游戏题解 Step-1 输入(重点) 输入n:int n;cin>>n; 输入数组: int a[1001][1001]; for(int i=1 ...
- NOIp2012D1T2 国王游戏 题解
国王游戏 洛谷P1080国王游戏 题解 这道题有个重要的性质:如果交换相邻两个大臣,获得金钱变化的有且只有这两个大臣.其余大臣得到的金钱不变. 我们考虑第 i i i个大臣和第 i + 1 i+1 i ...
- 随缘学习 扫雷游戏 题解
随缘学习 扫雷游戏 题解 作者名:nlc3030 学习目的:随缘学习,熟练下java的使用 题解: 01 这个扫雷游戏,通过题目知道就是定义一个二维数组,然后进行逐个查找进行扫雷 02 在写代码的时候 ...
- P1057传球游戏 题解
P1057传球游戏 题解 题目描述: 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:nnn个同学站成一个圆圈,其中的一个同学手里拿着一个球 ...
- P2356 弹珠游戏题解
P2356 弹珠游戏题解 先说都会的TIE两个点的题解- #include<bits/stdc++.h> using namespace std; int n; int a[10001][ ...
- Bzoj 2563: 阿狸和桃子的游戏 题解
2563: 阿狸和桃子的游戏 Time Limit: 3 Sec Memory Limit: 128 MB Submit: 970 Solved: 695 [Submit][Status][Dis ...
- [NOIP2010 普及组] 三国游戏 题解
一只蒟蒻,第一次写题解,有错误还望指正! [NOIP2010 普及组] 三国游戏 题目https://www.luogu.com.cn/problem/P1199 题意理解 废话不多说,我们先看题目. ...
最新文章
- 2022-2028年中国文化产业园投资分析及前景预测报告(全卷)
- TensorFlow快餐教程:程序员快速入门深度学习五步法
- sigprocmask和sigsuspend转
- ARC 没有自动释放内存
- VTK:Utilities之SortDataArray
- C++ template类模板实现栈 pop push
- JDBC学习笔记 day1
- 为什么你应该用Yarn而不是Npm来管理你的项目依赖?
- mongodb 启动脚本和配置
- hibernate注释映射_Hibernate一对多映射示例注释
- java 100个定时任务_Java定时任务解决方案
- WordPress SEO 完全指南
- 计算机键盘上删除,电脑键盘删除键是哪一个
- 如果你的下属不服从你得管理,你会怎么办?
- python画江苏_江苏高考数学再现算法流程图!学过编程的孩子都说So easy!
- excel如何转化成word文件
- 《阿丽塔:战斗天使》:人类与机器人真的有爱情吗?
- 2022年国家法定节假日放假时间安排
- WKWebView预初始化
- 回到1996,一起领略 JavaBeans 的真正力量
热门文章
- 微信 请求校验(确认请求来自微信服务器)
- 企业为什么要选择软文营销?
- Java Concurrency In Practice
- 一份详细的Google hacking语法(Google搜索语法)
- Python中的strip().split(‘\t‘)的用法和解释
- 辉太郎看前端(查找出字符串或数组中出现次数最多的字符)
- w3c标准html,W3C标准及规范
- 计算机系统硬盘拷贝,不用互助,轻松搞定新旧电脑间系统完整复制或硬盘更换!...
- 打印公司员工信息表java,打印模板 java
- Codeforces1442 D. Sum(dp+分治优化)