Problem

Description

一次小 \(G\) 和小 \(H\) 在玩寻宝游戏,有 \(n\) 个房间排成一列,编号为 \(1,2,…,n\),相邻房间之间都有 \(1\) 道门。其中一部分门上有锁(因此需要对应的钥匙才能开门),其余的门都能直接打开。

现在小 \(G\) 告诉了小 \(H\) 每把锁的钥匙在哪个房间里(每把锁有且只有一把钥匙),并作出 \(p\) 次指示:第 \(i\) 次让小 H 从第 \(S_i\) 个房间出发,去第 \(T_i\) 个房间寻宝。但是小 \(G\) 有时会故意在指令里放入死路,而小 \(H\) 也不想浪费多余的体力去尝试,于是想事先调查清楚每次的指令是否存在一条通路。

你是否能为小 \(H\) 作出解答呢?

Input Format

第一行三个整数\(n\),\(m\),\(p\),代表共有 \(n\) 个房间,\(m\) 道门上了锁,以及 \(p\) 个询问。

接下来 \(m\) 行每行有两个整数\(x\),\(y\),代表第 \(x\) 到第 \(x + 1\) 个房间的门上有把锁,并且这把锁的钥匙被放在了第 \(y\) 个房间里。输入保证 \(x\) 不重复。

接下来 \(p\) 行,其中第 \(i\) 行是两个整数 \(S_i\),\(T_i\),代表一次询问。

Output Format

输出 \(m\) 行,每行一个大写的 YESNO 分别代表能或不能到达。

Sample

Input 1

5 4 5
1 3
2 2
3 1
4 4
2 5
3 5
4 5
2 1
3 1

Output 1

YES
NO
YES
YES
NO

Input 2

此组样例满足特性:\(y \le x\) 恒成立

7 5 4
2 2
3 3
4 2
5 3
6 6
2 1
3 4
3 7
4 5

Output 2

YES
YES
NO
NO

Explanation

Explanation for Input 1

第一个询问 \(S = 2\)、\(T = 5\) 的一条可行路线是:\(2 \rightarrow 3 \rightarrow 2 \rightarrow 1 \rightarrow 2 \rightarrow 3 \rightarrow 4 \rightarrow 5\)。

Explanation for Input 2

第一个询问 \(2\) 和 \(1\) 房间之间没有锁所以为一条通路。

Range

测试点编号 n m 其他特性
1 \(\le 1000\) \(\le 1000\)
2 \(\le 1000\) \(\le 1000\)
3 \(\le 10^5\) \(\le 10^5\) \(y \le x\) 恒成立
4 \(\le 10^5\) \(\le 10^5\) \(y \le x\) 恒成立
5 \(\le 10^5\) \(\le 10^5\)
6 \(\le 10^5\) \(\le 10^5\)
7 \(\le 10^6\) \(\le 10^6\) \(y \le x\) 恒成立
8 \(\le 10^6\) \(\le 10^6\) \(y \le x\) 恒成立
9 \(\le 10^6\) \(\le 10^6\)
10 \(\le 10^6\) \(\le 10^6\)

Algorithm

线段树,单调栈。

Mentality

基本思路:设 \(r[i]\) 与 \(l[i]\) 为从 \(i\) 出发的能到达的区间,求出后对于每个询问 \(O(1)\) 判断就好。

这一题我们先从 \(60\) 分的做法看起:

  • 暴力拓展左右端点,复杂度 \(O(n^2)\),\(20pts\) 。
  • 对于所有 \(y\le x\) 的点用单调栈,\(40pts\) 。

暴力并不难,我们看看 \(40pts\) 的单调栈怎么做。其实不能算得上是什么神仙思路,类似于并查集,各扇门将序列分成了一些小区间,如果你通过此区间能到达其他区间,那么其他区间能到达的所有区间你也能到达。这就是此题单调栈的思路。

首先,既然所有 \(y\le x\) ,可以知道,我们向左走,一旦碰到一扇门就肯定走不过去了,那么我们只需要考虑最多能向右走多远就行了。

这个向右走的过程我们使用单调栈来维护:如果我们此时能到达的区间里有通向右边相邻区间的钥匙,那一旦到达当前区间,我必定能到达下一个区间,那么将两个区间合并为一个区间即可。

此处应有小代码:

bool pd(int x)
{
return key[r[x]]>=l[x]&&key[r[x]]<=r[x];
}
for(int i=n;i>=1;i--)
{
stack[++top]=r[i];//r[i]为初始区间右端点
while(pd(i))//如果当前区间右端点的钥匙在区间内
r[i]=stack[--top];//更新右端点并栈内合并区间
}

\(40pts\) 解决了,那 \(100\) 分呢?

其实也很简单,我们唯一的难点仅在于左端点也会更新。所以我们只需要能在当前右端点条件下快速求出左端点能扩展到多远即可。

根据 \(y\le x\) 的情况,我们可以类推得到:向左走时,一旦钥匙在门左边,那就肯定过不去;向右走时,一旦钥匙在门右边,那肯定也过不去。

于是我们可以求出 \(ll[i]\) 与 \(rr[i]\) 来代表 \(i\) 所能到达区间的理论上界 (最大的左右端点只可能是 \(ll\) 与 \(rr\))。

那不难发现,我当前能走到的区间是 \([l,r]\) ,而对于 \(l\) 的扩展,一定能扩展到 \([ll,l-1]\) 里最右边的,钥匙位置 \(>r\) 的位置后边。

为什么呢?因为根据我们的筛法,区间 \([ll,l-1]\) 内的门的钥匙肯定都在门右边 (不然 \(ll\) 只会更右) ,则此区间内门的钥匙要么 \(\le r\) 要么 \(>r\) ,同时又在自己右边,那钥匙位置 \(\le r\) 的门肯定都可以打开的呀!

那么和之前是一模一样的,只是判断单调栈弹出之前先更新左端点即可:

bool pd(int x)
{
update_l(x);
return key[r[x]]>=l[x]&&key[r[x]]<=r[x];
}
for(int i=n;i>=1;i--)
{
stack[++top]=r[i];
while(pd(i))
r[i]=stack[--top];
}

至于具体怎么更新左端点呢?我们只需要找到区间 \([ll,l-1]\) 中,第一个 \(\ge r[i]\) 的位置就好。我们可以用线段树维护区间钥匙位置最大值,并在线段树上查找就好,设查找到的位置为 \(pos\) ,左端点更新为 \(pos+1\) 即可。

Code

#include <cstdio>
#include <iostream>
using namespace std;
#define ls (o << 1)
#define rs ((o << 1) + 1)
#define mid ((l + r) >> 1)
int n, m, Q, key[1000001], ll[1000001], rr[1000001], l[1000001], r[1000001];
int now, top, stack[1000001];
int L, R, X, ans, maxx[4000001];
void build(int o, int l, int r) {
if (l == r) {
maxx[o] = key[l];
return;
}
build(ls, l, mid), build(rs, mid + 1, r);
maxx[o] = max(maxx[ls], maxx[rs]);
}
void query(int o, int l, int r) {
if (ans) return;
if (l == r) {
ans = l;
return;
}
if (mid < R && maxx[rs] > X) query(rs, mid + 1, r); //显然先找右区间哇
if (mid >= L && maxx[ls] > X) query(ls, l, mid);
}
bool pd(int x) {
L = ll[x], R = l[x] - 1, X = r[x], ans = 0;
query(1, 1, n);
l[x] = !ans ? ll[x] : ans + 1; //更新左端点
return key[r[x]] >= l[x] && key[r[x]] <= r[x];
}
int main() {
freopen("4436.in", "r", stdin);
freopen("4436.out", "w", stdout);
cin >> n >> m >> Q;
int x, t, now, tp;
for (int i = 1; i <= m; i++) scanf("%d", &x), scanf("%d", &key[x]);
now = 1, tp = 1;
for (int i = 1; i <= n; i++) {
if (key[i - 1]) {
now = i;
if (key[i - 1] < i) tp = i;
}
ll[i] = tp, l[i] = now;
}
now = n, tp = n;
for (int i = n; i >= 1; i--) {
if (key[i]) {
now = i;
if (key[i] > i) tp = i;
}
rr[i] = tp, r[i] = now;
} //处理出 l,r,ll,rr
build(1, 1, n); //建树
stack[++top] = n;
for (int i = n; i >= 1; i--) {
stack[++top] = r[i];
while (pd(i)) r[i] = stack[--top];
} //求出 l,r
while (Q--) {
scanf("%d%d", &x, &t);
printf(t >= l[x] && t <= r[x] ? "YES\n" : "NO\n");
}
}

【HNOI 2018】游戏的更多相关文章

  1. [HNOI 2018]游戏

    Description 题库链接 有 \(n\) 个房间排成一列,编号为 \(1,2,...,n\) ,相邻的房间之间都有一道门.其中 \(m\) 个门上锁,其余的门都能直接打开.现在已知每把锁的钥匙 ...

  2. 【HNOI 2018】寻宝游戏

    Problem Description 某大学每年都会有一次 \(Mystery\ Hunt\) 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为新 ...

  3. [HNOI 2018]寻宝游戏

    Description 题库链接 给出 \(n\) 个 \(m\) 位的二进制数,在每一个二进制数间插入一个 & 或 | ,第 \(0\) 个数为 \(0\) , \(0,1\) 间也要插入符 ...

  4. 【题解】Luogu P4436 [HNOI/AHOI2018]游戏

    原题传送门 \(n^2\)过百万在HNOI/AHOI2018中真的成功了qwqwq 先将没门分格的地方连起来,枚举每一个块,看向左向右最多能走多远,最坏复杂度\(O(n^2)\),但出题人竟然没卡(建 ...

  5. HNOI 2018 简要题解

    寻宝游戏 毒瘤题. 估计考试只会前30pts30pts30pts暴力然后果断走人. 正解是考虑到一个数&1\&1&1和∣0|0∣0都没有变化,&0\&0& ...

  6. [洛谷P4436] HNOI/AHOI2018 游戏

    问题描述 一次小G和小H在玩寻宝游戏,有n个房间排成一列,编号为1,2,...,n,相邻的房间之间都有一道门.其中一部分门上锁(因此需要有对应的钥匙才能开门),其余的门都能直接打开.现在小G告诉了小H ...

  7. [HNOI 2018]道路

    Description 题库链接 给出一棵含有 \(n\) 个叶子节点的二叉树,对于每个非叶子节点的节点,其与左儿子相连的边为公路,其与右儿子相连的边为铁路.对于每个节点,选择一条与其儿子相连的铁路或 ...

  8. [HNOI 2018]排列

    Description 题库链接 给定 \(n\) 个整数 \(a_1, a_2, \dots, a_n, 0 \le ai \le n\) ,以及 \(n\) 个整数 \(w_1, w_2, \do ...

  9. [HNOI/AHOI2018]游戏

    题目描述 https://lydsy.com/JudgeOnline/upload/201804/%E6%B9%96%E5%8D%97%E4%BA%8C%E8%AF%95%E8%AF%95%E9%A2 ...

随机推荐

  1. 【node】node连接mongodb操作数据库

    1.下载第三方模块mongodb cnpm install mongodb --save 2.检测是否连接成功 1.引入第三方模块mongodb并创建一个客户端 const MongoClient = ...

  2. linux考试题改错

    符号链接和硬链接有什么区别? 改:符号链接存储文件路径,可以指向不同分区文件,源文件删除后失效. 改:硬链接指向文件索引节点,仅能指向同一分区文件,源文件删除后可以访问. 请描述文件和目录9位权限位的 ...

  3. Redis集合 安装 哨兵集群 配置

    redis相关 redis基础 redis发布订阅 redis持久化RDB与AOF redis不重启,切换RDB备份到AOF备份 redis安全配置 redis主从同步 redis哨兵集群 redis ...

  4. [No0000197]Windows用户都应该知道的运行命令

    通过"运行"命令,运行Windows丰富工具的方法.如果您知道工具或任务的相应"运行"命令,那么您就知道访问所述工具或任务的最快方法. 以下是我们最喜欢的Run ...

  5. The way to unwind the stack on Linux EABI

    I. probe the stack frame structure The original idea is to unwind the function call stack according ...

  6. SpringBoot-@RequestParam

    Request参数 在访问各种各样网站时,经常会发现网站的URL的最后一部分形如:?xxxx=yyyy&zzzz=wwww.这就是HTTP协议中的Request参数,它有什么用呢?先来看一个例 ...

  7. Lint found fatal errors while assembling a release target

    1.Android 打包错误信息 Generate signed Bundle or APK  打包时,报了一个错,错误信息如下: Error:Execution failed for task ´: ...

  8. 【学习笔记】Tensorflow+Inception-v3训练自己的数据

    导读 喵喵的,一个大坑.本文分为吐槽和干货两部分. 一.吐槽 大周末的,被导师扣下加班,嗨气,谁叫本狗子太弱鸡呢,看起来很简单的任务倒腾了两天还没完,不扣你扣谁? 自己刚接到微调Inception-v ...

  9. 【JVM】-NO.112.JVM.2 -【JDK11 HashMap详解-2-tab[i = (n - 1) & hash])剖析】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  10. 转载的web server实例

    asp.net—web server模拟网上购物 2014-05-08     我来说两句   来源:asp.net—web server模拟网上购物   收藏    我要投稿 在学vb的时候学到了a ...