Decription
小w喜欢打牌,某天小w与dogenya在一起玩扑克牌,这种扑克牌的面值都在1到n,原本扑克牌只有一面,而小w手中的扑克牌是双面的魔术扑克(正反两面均有数字,可以随时进行切换),小w这个人就准备用它来出老千作弊。小w想要打出一些顺子,我们定义打出一个l到r的顺子需要面值为从l到r的卡牌各一张。小w想问问你,他能否利用手中的魔术卡牌打出这些顺子呢?
Solution
我们将一副牌对应的数连上边,不难发现当一个长度为 n n n 的区间里面有 n n n 条边时,才能打出顺子。
所以找出树来就可以了,用并查集维护一下,dfs出所有的树来。
那包含树的区间都是No的,我们记录每个树的区间,相当于做一次线段覆盖。
Code
/*
* @Name: C
* @Author: Lovely_XianShen
* @Date: 2019-10-29 20:30:54
* @Aqours!Sunshine!!
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int fa[N];
vector<int> mp[N];
vector<int> q;
bool vis[N];
int minn, maxx, n, k, m;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * f;
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
inline void connect(int x, int y) {
if (find(x) != find(y))
fa[find(x)] = y;
return;
}
void dfs(int x) {
if (vis[x])
return;
minn = min(minn, x);
maxx = max(maxx, x);
vis[x] = 1;
for (auto p : mp[x])
dfs(p);
}
struct node {
int l, r, i;
bool operator < (const node &x) const {
return r < x.r;
}
} qr[N];
int ans[N];
vector<node> v;
int main() {
n = read();
k = read();
for (int i = 1; i <= n; i++)
fa[i] = i;
while (k--) {
int x = read(), y = read();
if (find(x) == find(y))
q.push_back(x);
else {
connect(x, y);
mp[x].push_back(y);
mp[y].push_back(x);
}
}
for (auto i : q)
dfs(i);
for (int i = 1; i <= n; i++)
if (!vis[i]) {
minn = n;
maxx = 1;
dfs(i);
v.push_back({minn, maxx, 0});
}
m = read();
for (int i = 1; i <= m; i++)
qr[i].l = read(), qr[i].r = read(), qr[i].i = i;
sort(qr + 1, qr + m + 1);
sort(v.begin(), v.end());
int ml = 0;
for (int i = 1, i0 = 0; i <= m; i++) {
while (i0 < v.size() && qr[i].r >= v[i0].r) ml = max(ml, v[i0].l), i0++;
if (ml >= qr[i].l)
ans[qr[i].i] = 1;
}
for (int i = 1; i <= m; i++)
if (ans[i])
puts("No");
else
puts("Yes");
return 0;
}