LOJ #2508. 「AHOI / HNOI2018」游戏 拓扑排序
好神仙的一道题!
由于每个门对应的钥匙仅有一把,所以我们可以确定门和门之间的相对解锁顺序.
比如,解锁门 $(x,x+1)$ 的要是在 $[1,x]$ 之间的话 $x+1$ 无论如何也到不了 $x$ 这一侧,但是 $x$ 有可能可以到达 $x+1$ 这边.
所以我们就先去解锁 $x+1$,然后再去解锁 $x$,这样的话 $x$ 就可以直接继承 $x+1$ 的拓展结果了.
code:
#include <bits/stdc++.h> #define ll long long #define N 1000200 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int edges=1; int hd[N],to[N<<1],nex[N<<1],deg[N]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; deg[v]++; } int n,m,Q,p[N],tot,key[N]; queue<int>q; void topo() { int i,j; for(i=n;i;--i) if(!deg[i]) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); p[++tot]=u; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; --deg[v]; if(!deg[v]) q.push(v); } } } int L[N],R[N]; void cal(int x) { int l=x,r=x; while(1) { 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(l==pl&&r==pr) break; } L[x]=l,R[x]=r; } int main() { // setIO("input"); int i,j; scanf("%d%d%d",&n,&m,&Q); for(i=1;i<=m;++i) { int x,y; scanf("%d%d",&x,&y); key[x]=y; if(y<=x) add(x+1,x); else add(x,x+1); } topo(); for(i=1;i<=n;++i) L[i]=R[i]=i; for(i=1;i<=n;++i) cal(p[i]); while(Q--) { int s,t; scanf("%d%d",&s,&t); if(L[s]<=t&&t<=R[s]) printf("YES\n"); else printf("NO\n"); } return 0; }