有n n n 个房间排成一列,编号为1 , 2 , . . . , n 1,2,...,n 1 , 2 , . . . , n 相邻的房间之间都有一道门。其中一部分们上锁(因此需要有对应的钥匙才能开门),其余的门都能直接打开。
现在小G告诉了小H每把锁的钥匙在哪个房间里(每把锁有且只有一把钥匙与之对应) ,并作出p p p 次指示:
第i i i 次让小H从第S i S_i S i 个房间出发到T i T_i T i 个房间里。但是小G有时会故意在指令中放入死路,而小H也不想浪费多余的体力去尝试,于是想事先调查清楚每次的指令是否会存在一条通路。
1 ≤ n , p ≤ 1 0 6 , 0 ≤ m < n , 1 ≤ x , y , S i , T i < n 1\le n,p\le 10^6,0\le m <n,1\le x,y,S_i,T_i < n 1 ≤ n , p ≤ 1 0 6 , 0 ≤ m < n , 1 ≤ x , y , S i , T i < n ,保证x x x 不重复
Links Luogu P4436
Solution 容易发现,从一个房间开始后得到的这个可达区间一定是连续的一段,且一开始的锁把序列变成了几段,最暴力的想法是对于每一段,暴力地一左一右的扩展段
考虑优化掉一些重复转移,如果这个钥匙在这个门的右边,则只有右边的这段能扩展左边这段;否则右边的永远不可能更新到左边。即如果钥匙在门的右边,则先扩展左边这段再扩展右边;否则先扩展右边
按这个拓扑序暴力更新答案,复杂度O ( n + m ) O(n+m) O ( n + m )
Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #include <bits/stdc++.h> #define x first #define y second #define y1 Y1 #define y2 Y2 #define mp make_pair #define pb push_back using namespace std ;typedef long long LL;typedef pair<int , int > pii;template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0 ; }template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0 ; }inline void proc_status () { ifstream t ("/proc/self/status" ) ; cerr << string (istreambuf_iterator <char > (t), istreambuf_iterator <char > ()) <<endl ; } inline int read () { int sum = 0 , fl = 1 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) if (ch == '-' ) fl = -1 ; for (; isdigit (ch); ch = getchar()) sum = (sum << 3 ) + (sum << 1 ) + ch - '0' ; return sum * fl; } const int Maxn = 1e6 + 100 ;int N, M, P, Pos[Maxn];int L[Maxn], R[Maxn], Belong[Maxn];int e, Begin[Maxn], To[Maxn << 1 ], Next[Maxn << 1 ], deg[Maxn];inline void add_edge (int x, int y) { To[++e] = y; Next[e] = Begin[x]; Begin[x] = e; ++deg[y]; }inline void Solve () { int cnt = 1 ; L[1 ] = R[1 ] = 1 ; for (int i = 2 ; i <= N; ++i) { if (Pos[i - 1 ]) { L[++cnt] = i; if (Pos[i - 1 ] <= i - 1 ) add_edge (cnt, cnt - 1 ); else add_edge (cnt - 1 , cnt); } R[cnt] = i; } for (int i = 1 ; i <= cnt; ++i) for (int j = L[i]; j <= R[i]; ++j) Belong[j] = i; static queue <int > Q; for (int i = 1 ; i <= cnt; ++i) if (!deg[i]) Q.push(i); while (!Q.empty()) { int x = Q.front(), fl = 1 ; Q.pop(); while (fl) { fl = 0 ; int pos1 = Pos[L[x] - 1 ], pos2 = Pos[R[x]]; while (L[x] <= pos1 && pos1 <= R[x]) fl = 1 , L[x] = L[Belong[L[x] - 1 ]], pos1 = Pos[L[x] - 1 ], pos2 = Pos[R[x]]; while (L[x] <= pos2 && pos2 <= R[x]) fl = 1 , R[x] = R[Belong[R[x] + 1 ]], pos2 = Pos[R[x]]; while (L[x] <= pos1 && pos1 <= R[x]) fl = 1 , L[x] = L[Belong[L[x] - 1 ]], pos1 = Pos[L[x] - 1 ], pos2 = Pos[R[x]]; } for (int i = Begin[x]; i; i = Next[i]) { int y = To[i]; --deg[y]; if (!deg[y]) Q.push(y); } } while (P--) { int x = read(), y = read(); if (L[Belong[x]] <= y && y <= R[Belong[x]]) puts ("YES" ); else puts ("NO" ); } } inline void Input () { N = read(), M = read(), P = read(); for (int i = 1 ; i <= M; ++i) { int x = read(), y = read(); Pos[x] = y; } } int main () {#ifdef hk_cnyali freopen("A.in" , "r" , stdin ); freopen("A.out" , "w" , stdout ); #endif Input(); Solve(); return 0 ; }