IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> [APIO2022] 游戏 题解 -> 正文阅读

[数据结构与算法][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

略微压行,代码很短,只有 700 多 B。

#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;

int n,k,l[maxn],r[maxn];vector<int> GA[maxn],rev[maxn];
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 true;
	int midu=(l[u]+r[u])>>1,midv=(l[v]+r[v])>>1;
	if (l[u]>midv) {l[v]=midv+1;return upd(v);}
	if (r[v]<=midu) {r[u]=midu;return upd(u);}
	return false;
}
bool upd(int u){
	for (auto v:GA[u]) {if(chk(u,v))return true;}
	for (auto v:rev[u]) {if (chk(v,u))return true;}
	return false;
}
int add_teleporter(int u,int v){GA[u].push_back(v),rev[v].push_back(u);return chk(u,v);}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-18 23:32:11  更:2022-06-18 23:32:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:50:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码