题意
有$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(); }