去年省选的时候这题给我乱搞整过去整过去了,也是虐心了。。。。
因此固然是来说正儿八经的正确作法啦。ios
很明显,咱们须要预处理答案。设\(L[i],R[i]\)表示从\(i\)出发可以到达的区间范围。
如今咱们要作的就是预处理这个\(L[i],R[i]\)。
首先考虑一个点如何向外暴力拓展,若是它在拓展过程当中碰到了一个已经被拓展过的节点,那么显然也能够到达那个点能够到达的全部位置,而后直接并一下就好啦。
而后如今咱们要肯定拓展的顺序。
对于一个门\((x,x+1)\)而言,若是钥匙在\([1,x]\)这段内,显然只有在\([1,x]\)这一侧才能拓展到\([x+1,n]\),因此必定先拓展\(x+1\)再拓展\(x\),因此连边\(x+1\rightarrow x\),反过来同理。
而后拓扑序肯定拓展顺序。
这样子每一个点被拓展的次数就是线性的啦QwQspa
#include<iostream> #include<cstdio> #include<queue> using namespace std; #define MAX 1000100 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Line{int v,next;}e[MAX]; int h[MAX],cnt=1,dg[MAX]; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;dg[v]+=1;} int n,m,Q,p[MAX],tot,key[MAX]; void Topsort() { queue<int> Q; for(int i=n;i;--i)if(!dg[i])Q.push(i); while(!Q.empty()) { int u=Q.front();Q.pop();p[++tot]=u; for(int i=h[u];i;i=e[i].next) if(!--dg[e[i].v])Q.push(e[i].v); } } int L[MAX],R[MAX]; void Calc(int x) { int l=x,r=x; while(233) { int pl=l,pr=r; while(l>1&&(!key[l-1]||(l<=key[l-1]&&key[l-1]<=r)))l=L[l-1]; while(r<n&&(!key[r]||(l<=key[r]&&key[r]<=r)))r=R[r+1]; if(pl==l&&pr==r)break; } L[x]=l;R[x]=r; } int main() { n=read();m=read();Q=read(); for(int i=1;i<=m;++i) { int x=read(),y=read();key[x]=y; if(y<=x)Add(x+1,x); else Add(x,x+1); } Topsort(); for(int i=1;i<=n;++i)L[i]=R[i]=i; for(int i=1;i<=n;++i)Calc(p[i]); while(Q--) { int S=read(),T=read(); if(L[S]<=T&&T<=R[S])puts("YES"); else puts("NO"); } return 0; }