游戏
题目背景:
分析:拓扑排序
这道题好神啊我不会······考场上打了60分暴力,被卡成40,其他人不管是乱搞还是正解,还是什么奇奇怪怪的玄学都过了,感觉内心崩溃,直接说正解吧,考虑一扇门,如果钥匙在左边,那么显然只能从左边才可能到右边,并且,如果左边可以到右边那么右边的可以到的区间,左边的一定也可以到,那么我们应该先处理右边,然后之后在判断左边是否能到右边,那么我们就可以根据这个关系直接按照一个拓扑序来处理对应点能够到达的区间,然后每次判断能否扩展,就可以了,比较显然的是,一个节点显然只会从左边扩展一次,从右边扩展一次,被当做停止节点多次,但是显然停止节点总次数是O(n),所以,总复杂度是O(n)。
Source:
/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
inline char read() {
static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}
///*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}
template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}
inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/
inline void write(bool flag) {
if (flag) write_char('Y'), write_char('E'),
write_char('S'), write_char('\n');
else write_char('N'), write_char('O'), write_char('\n');
}
const int MAXN = 1000000 + 10;
int n, m, t, x, y, cnt;
int l[MAXN], r[MAXN], id[MAXN], pos[MAXN], p[MAXN], deg[MAXN];
bool left[MAXN], right[MAXN];
inline void solve() {
R(n), R(m), R(t);
for (int i = 1; i <= m; ++i) R(x), R(y), pos[x] = y;
id[1] = cnt = 1;
for (int i = 2; i <= n; ++i) id[i] = (!pos[i - 1]) ? cnt : ++cnt;
cnt = 0;
for (int i = 1; i <= n; ++i) {
if (pos[i] != 0) {
if (pos[i] > i) left[id[i + 1]] = true, deg[id[i + 1]]++;
else right[id[i]] = true, deg[id[i]]++;
p[++cnt] = id[pos[i]];
}
}
cnt++;
static int q[MAXN];
int head = 0, tail = 0;
for (int i = 1; i <= cnt; ++i) if (deg[i] == 0) q[++tail] = i;
while (head < tail) {
int cur = q[++head];
if (cur != 1 && left[cur] == false)
if (--deg[cur - 1] == 0) q[++tail] = cur - 1;
if (cur != cnt && right[cur] == false)
if (--deg[cur + 1] == 0) q[++tail] = cur + 1;
}
for (int i = 1; i <= cnt; ++i) {
int cur = q[i];
bool flag = true;
l[cur] = r[cur] = cur;
while (flag) {
flag = false;
while (left[cur] && p[l[cur] - 1] >= l[cur] &&
p[l[cur] - 1] <= r[cur]) l[cur] = l[l[cur] - 1], flag = true;
while (right[cur] && p[r[cur]] >= l[cur] &&
p[r[cur]] <= r[cur]) r[cur] = r[r[cur] + 1], flag = true;
}
}
while (t--) R(x), R(y), x = id[x], y = id[y], write(y >= l[x] && y <= r[x]);
}
int main() {
//freopen("in.in", "r", stdin);
solve();
flush();
return 0;
}