5288: [Hnoi2018]游戏
5288: [Hnoi2018]游戏
分析:
考虑y<=x的怎么做,那么只能从左边走到右边。我们可以从最右边的点开始,一次确定每个点往右边可以走多少。
L[x],R[x]分别是x向左向右最远走到的位置,初始L[x]=x,R[x]=x。R[n]=n,然后看n-1,如果n-1存在打开n-1这扇门的钥匙,那么说明n-1可以到n,相应的R[n-1]=R[n]。同样的考虑i,如果i可以打开第i扇门,那么R[i]=R[i+1],继续判断如果i可以打开第R[i]扇门,那么R[i]=R[R[i]]……
于是这样可以求出每个往右延伸的范围。复杂度的证明:每扇门只会被打开一次,每个点只会被求扫一次,于是复杂度是$O(n)$
如果y不小于x,考虑怎么做。将两个点之间的边确定方向(如果钥匙在左边,那么边是左->右,否则是右->左),然后对于找到一个点x,它既能向左走也可以向右走,从这个点开始,往左走到的是y,那么x->y这一段和y<=x的性质一样,做法也一样,扫一遍即可,往右走同理。最后处理x,直接暴力处理即可。
复杂度:每个点只会存在于一条链中,暴力处理的点总复杂度是O(n)的。
如果一条边上没有门呢?没法定向了,缩点即可。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
int a[N], b[N];
int n, m, Q; namespace BF1{
int L[], R[]; bool vis[]; vector<int> vec[], d;
void Mark(int x) {
for (int j = ; j < (int)vec[x].size(); ++j) vis[vec[x][j]] = ;
}
void Calc(int x) {
L[x] = R[x] = x;
for (int i = ; i <= n; ++i) vis[i] = ;
for (int i = ; i < (int)d.size(); ++i)
vis[d[i]] = ;
Mark(x);
while () {
if (!vis[R[x]] && !vis[L[x] - ]) break;
if (vis[R[x]]) {
R[x] ++; Mark(R[x]);
}
if (vis[L[x] - ]) {
L[x] --; Mark(L[x]);
}
}
}
void Main() {
for (int i = ; i <= m; ++i) vec[b[i]].push_back(a[i]);
for (int i = ; i <= m; ++i) vis[a[i]] = ;
for (int i = ; i < n; ++i) if (!vis[i]) d.push_back(i);
for (int i = ; i <= n; ++i) Calc(i);
while (Q--) {
int s = read(), t = read();
if (L[s] <= t && t <= R[s]) puts("YES");
else puts("NO");
}
}
} int head[N], fa[N], vis[N], chu[N], nxt[N], pre[N], L[N], R[N], pos[N], En;
vector<int> d;
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
inline void Union(int x,int y) { if (x != y) fa[y] = x;}
inline void add_edge(int x,int y) { x = find(x), y = find(y); chu[x] ++; } void Calc(int x) {
int z = x;
while (z >= && chu[z] != ) z = pre[z]; if (z < ) z = nxt[z];
for (int i = z; i <= x; i = nxt[i]) {
L[i] = i;R[i] = i;
int now = pre[L[i]];
if (now < z) continue;
while (L[i] <= pos[now] && pos[now] <= R[i]) {
L[i] = L[now], now = pre[L[i]];
}
}
z = x;
while (z <= n && chu[z] != ) z = nxt[z]; if (z > n) z = pre[z];
for (int i = z; i >= x; i = pre[i]) {
L[i] = i;R[i] = i;
int now = R[i];
if (nxt[now] > z) continue;
while (L[i] <= pos[now] && pos[now] <= R[i]) {
R[i] = R[nxt[now]], now = R[i];
}
}
while () {
bool f = ;
if (L[x] <= pos[R[x]] && pos[R[x]] <= R[x]) R[x] = nxt[R[x]], f = ;
if (L[x] <= pos[pre[L[x]]] && pos[pre[L[x]]] <= R[x]) L[x] = pre[L[x]], f = ;
if (!f) break;
}
}
void solve() {
for (int i = ; i <= m; ++i) vis[a[i]] = ;
for (int i = ; i <= n; ++i) fa[i] = i;
for (int i = ; i < n; ++i) if (!vis[i]) Union(i, i + );
int last = ;
for (int i = ; i <= n; ++i)
if (find(i) == i) pre[i] = last, nxt[last] = i, last = i;
nxt[last] = n + ; pre[n + ] = last; for (int i = ; i <= m; ++i) {
a[i] = find(a[i]), b[i] = find(b[i]);
if (b[i] <= a[i]) add_edge(a[i], nxt[a[i]]);
else add_edge(nxt[a[i]], a[i]);
pos[a[i]] = b[i];
}
for (int i = ; i <= n; i = nxt[i]) {
if (chu[i] == || (i == nxt[] && chu[i] == ) || (i == pre[n + ] && chu[i] == ))
Calc(i);
}
}
int main() {
n = read(), m = read(), Q = read();
for (int i = ; i <= m; ++i)
a[i] = read(), b[i] = read();
if (n <= && m <= ) { BF1::Main(); return ; }
if (m == ) { while (Q --) puts("YES"); return ; }
solve();
for (int i = ; i <= n; ++i) if (!L[i]) L[i] = L[find(i)];
for (int i = n; i >= ; --i) if (R[i]) R[i] = nxt[R[i]] - ;
for (int i = ; i <= n; ++i) if (!R[i]) R[i] = R[find(i)]; while (Q--) {
int s = read(), t = read();
if (L[s] <= t && t <= R[s]) puts("YES");
else puts("NO");
}
return ;
}
代码:
5288: [Hnoi2018]游戏的更多相关文章
- bzoj 5288: [Hnoi2018]游戏
Description Solution 乱搞能A的题,毁我青春 记忆化一下扩展过程 只要不是从 \(1\) 枚举到 \(n\) 去扩展都可以 \(AC\) 于是 \(random\_shuffle\ ...
- 【BZOJ5288】[HNOI2018]游戏(拓扑排序)
[BZOJ5288][HNOI2018]游戏(拓扑排序) 题面 BZOJ 洛谷 题解 去年省选的时候这题给我乱搞整过去整过去了,也是虐心了.... 所以当然是来讲正儿八经的正确做法啦. 很明显,我们需 ...
- BZOJ.5288.[AHOI/HNOI2018]游戏(思路 拓扑)
BZOJ LOJ 洛谷 考虑如何预处理每个点能到的区间\([l,r]\). 对于\(i,i+1\)的一扇门,如果钥匙在\(i\)的右边,连边\(i\to i+1\),表示从\(i\)出发到不了\(i+ ...
- 【BZOJ5288】[HNOI2018]游戏(乱搞?)
[BZOJ5288][HNOI2018]游戏(乱搞?) 题面 BZOJ 洛谷 题面自己到洛谷上看把 题解 考场上乱搞拿到了\(90\)分,简直不敢相信. 回家把代码再交了一份直接就\(AC\)了??? ...
- [HNOI2018]游戏[拓扑排序]
题意 题目链接 分析 先将没有锁的房间缩点,首先有一个 \(O(n^2)\) 的想法:从每个点出发,每次检查能否向两边扩张. 容易发现门和门之间如果有锁,必然只有一方能够开锁(只有一把钥匙),并且能够 ...
- 【比赛】HNOI2018 游戏
考试的时候线段树区间查询的return条件打成了l==r....于是光荣爆20(线段树都不会打了?) 看膜博士的题解 #include<bits/stdc++.h> #define ui ...
- [BZOJ5288][HNOI2018]游戏(拓扑排序)
传送门:https://www.luogu.org/problemnew/show/P4436 20分的暴力加一个Random_shuffle就A了.我还能说什么.. 不过这个也不是毫无道理,复杂度应 ...
- bzoj5288: [Hnoi2018]游戏
我还是太年轻了... 考场上就是直接枚举预处理当前位置左右延伸到的最远距离,好像是水了20.. 然后噶爷爷居然随机一下就AC了????mengbier #include<cstdio> # ...
- # HNOI2012 ~ HNOI2018 题解
HNOI2012 题解 [HNOI2012]永无乡 Tag:线段树合并.启发式合并 联通块合并问题. 属于\(easy\)题,直接线段树合并 或 启发式合并即可. [HNOI2012]排队 Tag:组 ...
随机推荐
- The videobuf2 API【转】
转自:https://blog.csdn.net/paul_liao/article/details/8986999 The videobuf2 API Author:CJOK Contact:cjo ...
- 驱动开发--【字符设备、块设备简介】【sky原创】
驱动开发 字符设备,块设备,网络设备 字符设备 以字节流的方式访问, 不能随机访问 有例外,显卡.EEPROM可以随机访问 EEPROM可以擦写1亿次,是一种字符设备,可以随机访问 读写是 ...
- pyspider使用
#!/usr/bin/env python # -*- encoding: utf-8 -*- # Created on 2018-11-08 22:33:55 # Project: qsbk fro ...
- X-Forwarded-For 的一些理解
X-Forwarded-For 是一个 HTTP 扩展头部, 主要是为了让 Web 服务器获取访问用户的真实 IP 地址(其实这个真实未必是真实的,后面会说到). 那为什么 Web 服务器只有通过 X ...
- js学习、备忘
字符串使用单引号’abc’.(双引号也行.推荐:html→双引号,js→单引号)===严格等于.!==严格不等于if(x) 当x为undefined.null和0的时候都为false:需注意当x为0 ...
- PYTHON-模块time&datetime+ 目录规范
1.目录规范 ***** (1)文件夹的规范写法 bin 可执行文件 conf 配置文件 core 主要业务逻辑 db 数据文件 lib 库 (公共代码 第三方模块) log 日志文件 readme ...
- STM32F412应用开发笔记之七:片上ADC的应用测试
在我们的应用项目中需要采集一些模拟量,这些量使用MCU自带的ADC就可以满足要求.在NUCLEO-F412ZG实验板上的STM32F412ZG有一个16通道的ADC,我们试验用它采集几个数据. 在NU ...
- Keepalived详解之 - LVS(IPVS)管理工具ipvsadm使用指南
ipvsadm是什么? ipvsadm是用来配置.维护或者查看Linux内核当中virtual server table的一个工具, LVS(Linux virtual server)能基于一个集群当 ...
- 获取修改value
val() 方法,获取和修改有value属性的元素,有value属性的元素有input.botton.select等.相当于JavaScript中的value. <!DOCTYPE html&g ...
- 计算机编码--c语言中输出float的十六进制和二进制编码
c语言中没有可以直接打印float类型数据的二进制或者十六进制编码的输出格式, 因此,需要单独给个函数,如下: unsigned int float2hexRepr(float* a){ unsign ...