拓扑排序优化暴力
啥题都要看题解,我咋这么菜!!!……
SOL:
我们需要预处理出两个数组(l[i],r[i],i)点到左/右最远能到达那个点,这样便于(O(1))回答询问
当然可以左右枚举,但是为了节省时间,我们想要继承左右点可到达的信息
于是枚举顺序就十分重要了
门((x,x+1)),若钥匙在([1,x]),只有在([1,x])才能拓展到([x+1,n]),所以先拓展(x+1)再拓展(x),连边(x+1→x);反之同理
用拓扑排序处理顺序,然后枚举可到达即可
最开始加度数为0的点时从大到小,因为我们拓展时是先左端点再右端点,这样更快 我不会告诉你反过来会超时
时间复杂度线性
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e6+4;
int n,m,Q,key[N],l[N],r[N],deg[N];
vector<int>e[N];
inline void calc(int x){
static int pl,pr;
pl=pr=x;
while(1){
while(pl>1&&(!key[pl-1]||(pl<=key[pl-1]&&key[pl-1]<=pr)))pl=l[pl-1];
while(pr<n&&(!key[pr]||(pl<=key[pr]&&key[pr]<=pr)))pr=r[pr+1];
if(pl==l[x]&&pr==r[x])return;
l[x]=pl;r[x]=pr;
}
}
inline void topsort(){
queue<int>q;
for(int i=n;i;i--)if(!deg[i])q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
calc(x);
for(auto v:e[x])
if(!(--deg[v]))q.push(v);
}
}
int main(){
n=read();m=read();Q=read();
for(int i=1;i<=n;i++)l[i]=r[i]=i;
for(int i=1,x,y;i<=m;i++){
x=read();key[x]=y=read();
if(y<=x){e[x+1].push_back(x);deg[x]++;}
else{e[x].push_back(x+1);deg[x+1]++;}
}
topsort();
while(Q--){
static int x,y;
x=read();y=read();
if(l[x]<=y&&y<=r[x])puts("YES");
else puts("NO");
}
return (0-0);
}