题解
一个点的影响区间显然是一段连续的区间
这样一个显然的(O(n^2))暴力就是我们可以将一个点向左右扩展,处理出从这个点出发能到达的左右端点(lp,rp)
然后考虑怎么优化这个暴力
首先如果我们从点(u)向左扩展到(l),并且这个(l)已经被扩展过
那么我们就可以直接让(lp[u])变成(lp[l])
所以我们如果能确定一个顺序使得更新到这个点的时候所有ta能更新的点已经被更新过的话这个复杂度就变得肥肠优秀了
我们考虑每个门和钥匙((x,Key_x))
如果钥匙在门的左边,那么显然门右边的点都过不了这个门
那么我们就对这个门(x)连一条((x+1,x))边
表示反正右边的点过不了门,所以先处理门右边的部分,再处理门左边的部分
反之就连((x,x+1))
然后拓扑排序的时候当处理到这个点的时候ta能更新到的点都已经被更新了
所以直接暴力更新就可以了
然后注意如果两个屋子之间没有门就把他们缩起来
复杂度(O(n+m))
代码
/*
Key[i] <= i 钥匙在左门在右
add_edge(i+1,i)
Key[i] > i 钥匙在右门在左
add_edge(i,i+1)
*/
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 1000005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
bool exist[M] ;
int n , m , cnt , num ;
int f[M] , idx[M] , Key[M] ;
int d[M] , hea[M] , xp[M] , yp[M] , lp[M] , rp[M] ;
struct E {
int nxt , to ;
} edge[M] ;
int find(int x) {
if(f[x] != x)
f[x] = find(f[x]) ;
return f[x] ;
}
inline void add_edge(int from , int to) {
edge[++num].nxt = hea[from] ;
edge[num].to = to ;
hea[from] = num ;
}
inline void topsort() {
queue < int > q ;
for(int i = 1 ; i <= cnt ; i ++) {
lp[i] = rp[i] = i ;
if(!d[i])
q.push(i) ;
}
while(!q.empty()) {
int u = q.front() ; q.pop() ;
bool suc = true ;
while(suc) {
suc = false ;
if(lp[u] > 1 && Key[lp[u] - 1] >= lp[u] && Key[lp[u] - 1] <= rp[u])
lp[u] = lp[lp[u] - 1] , suc = true ;
if(rp[u] < cnt && Key[rp[u]] <= rp[u] && Key[rp[u]] >= lp[u])
rp[u] = rp[rp[u] + 1] , suc = true ;
}
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
-- d[v] ;
if(!d[v])
q.push(v) ;
}
}
}
int main() {
n = read() ; m = read() ; int Case = read() ;
for(int i = 1 ; i <= n ; i ++)
f[i] = i ;
for(int i = 1 ; i <= m ; i ++) {
xp[i] = read() ; yp[i] = read() ;
exist[xp[i]] = true ;
}
for(int i = 1 ; i < n ; i ++) {
if(exist[i]) continue ;
int x = find(i) , y = find(i + 1) ;
if(x != y) f[y] = x ;
}
for(int i = 1 ; i <= n ; i ++) {
if(find(i) != find(i - 1)) ++ cnt ;
idx[i] = cnt ;
}
for(int i = 1 ; i <= m ; i ++)
Key[idx[xp[i]]] = idx[yp[i]] ;
for(int i = 1 ; i < cnt ; i ++) {
if(Key[i] <= i) {
add_edge(i + 1 , i) ;
++ d[i] ;
}
else {
add_edge(i , i + 1) ;
++ d[i + 1] ;
}
}
topsort() ;
int x , y ;
while(Case --) {
x = read() ; y = read() ;
if(idx[y] >= lp[idx[x]] && idx[y] <= rp[idx[x]])
printf("YES
") ;
else printf("NO
") ;
}
return 0 ;
}