題意
有$n$個房間,第$i$個房間與第$i+1$個房間之間有一扇門,有些門上了鎖。已知全部上了鎖的門的編號,以及每一把鎖在哪一個房間,有多組詢問:可否從$a$房間到達$b$房間?node
思路
考慮優化暴力。c++
對於每個節點,維護L[i],R[i],表示該節點可以到達最左右極點。優化
對於任意一扇上了鎖的門,若是鑰匙在門的左邊,那麼這扇門右邊的房間確定都到不了左邊的房間,而左邊的房間有可能達到右邊的房間。若是鑰匙在門的右邊則同理。spa
也就是說,對於一扇上了鎖的門,右邊的每個節點的[L,R]都不可能包含左邊的節點的[L,R],而反過來是有可能的。code
能夠考慮這樣的一種拓展順序:排序
對於拓展序列中的每個節點,位於它前面的任意節點都不可能包含它的區間。get
顯然這樣的拓展順序是最優的,由於咱們的更新始終不會被幹擾。it
爲了獲得這樣的拓展順序,考慮採用拓撲排序。對於鑰匙在門左側的狀況,從右邊連向左邊的節點,反之亦然。而後跑一遍拓撲排序便可獲得咱們須要的拓展順序,最後暴力拓展便可。class
可是這樣寫仍是會T,因此須要進一步優化。程序
考慮這樣一種狀況:只有一個門上了鎖,而其餘全部門都沒有上鎖。
對於這樣的狀況,咱們的程序仍然有n的計算量,而事實上只須要1的計算量。
能夠對數據進行預處理,將不要鑰匙就能夠直接到達的點鎖在一塊兒,而後對縮完點的序列再進行拓撲排序,這樣對於上述狀況就能夠作的高效處理了。
代碼
無縮點環節,70分代碼
#include <bits/stdc++.h> using namespace std; namespace StandardIO { template<typename T> inline void read (T &x) { x=0;T f=1;char c=getchar(); for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1; for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0'; x*=f; } template<typename T> inline void write (T x) { if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10); putchar((x%10)+'0'); } } using namespace StandardIO; namespace Solve { const int N=1000010; int n,m,p; int key[N],l[N],r[N],indeg[N]; int cnt; int head[N]; struct node { int to,next; } edge[N<<1]; int num; int seq[N]; inline void add (int a,int b) { edge[++cnt].to=b,edge[cnt].next=head[a],head[a]=cnt,++indeg[b]; } inline void topsort () { queue<int> q; for (register int i=1; i<=n; ++i) if (!indeg[i]) q.push(i); while (!q.empty()) { int cur=q.front();q.pop(),seq[++num]=cur; l[cur]=r[cur]=cur; for (register int i=head[cur]; i; i=edge[i].next) { int to=edge[i].to; --indeg[to]; if (!indeg[to]) q.push(to); } } } inline void Main () { read(n),read(m),read(p); for (register int i=1; i<=m; ++i) { int x,y; read(x),read(y); key[x]=y; if (y>x) add(x,x+1); else add(x+1,x); } topsort(); int counter=0; for (register int i=1; i<=n; ++i) { int now=seq[i]; while (1) { int tl=l[now],tr=r[now]; while (tl>1&&(!key[tl-1]||(tl<=key[tl-1]&&key[tl-1]<=tr))) tl=l[tl-1]; while (tr<n&&(!key[tr]||(tl<=key[tr]&&key[tr]<=tr))) tr=r[tr+1]; if (tl==l[now]&&tr==r[now]) break; l[now]=tl,r[now]=tr; } } for (register int i=1; i<=p; ++i) { int s,t; read(s),read(t); if (l[s]<=t&&t<=r[s]) puts("YES"); else puts("NO"); } } } int main () { Solve::Main(); }