杂题

有向图,问点 \(u\) 能否通过标号在 \(l\)\(r\) 之间的边到达 \(v\)

\(n,q \leq 50000,m\leq 100000\)

#include<cstdio>
#include<cstring>
const int H=40000040;
char G[H],*_=G;
int read(){
	int x=0;
	while(*_<'0'||'9'<*_)_++;
	while('0'<=*_&&*_<='9')x=x*10+(*_++^'0');
	return x;
}
const int N=50050;
int tp;
#include<cmath>
#include<bitset>
std::bitset<N>f[N],Q[460],tmp;
#include<vector>
std::vector<int>ql[N<<1],qr[N<<1];
struct edge{
	int u,v;
}e[N<<1];
struct query{
	int u,v;
}h[N];
struct go{
	go*net;int to,id;
}ea[N<<1],*tot=ea,*head[N];
int p[N<<1],d[N],qq[N];
void work(){
	int i,l,r,n=read(),m=read(),q=read(),size=sqrt(m);
	memset(d,0,sizeof(int)*(n+1));
	for(i=0;i<n;i++)f[i].reset();Q[0].reset();
	for(i=0;i<=m;i++)ql[i].clear(),qr[i].clear();
	memset(head,0,sizeof(go*)*(n+1)),tot=ea; 
	for(i=0;i<m;i++)e[i].u=read(),e[i].v=read(),*++tot={head[e[i].u],e[i].v,i},head[e[i].u]=tot,d[e[i].v]++;
	for(i=0;i<q;i++)h[i].u=read(),h[i].v=read(),l=read()-1,r=read()-1,ql[l].push_back(i),qr[r+1].push_back(i),f[h[i].v-1][i]=1;
	for(i=0;i<m;i++){
		for(int j:ql[i])Q[i/size][j]=1;
		for(int j:qr[i])Q[i/size][j]=0;
		if((i+1)%size==0)Q[(i+1)/size]=Q[i/size];
	}
	int *hh=qq,*tt=qq,cnt=0;
	for(i=1;i<=n;i++)if(!d[i])*++tt=i;
	while(++hh<=tt){
		for(go*ii=head[*hh];ii;ii=ii->net){
			d[ii->to]--,p[cnt++]=ii->id;
			if(!d[ii->to])*++tt=ii->to;
		}
	}
	for(i=m-1;i>=0;i--){
		tmp.reset();
		if(p[i]/size!=0)tmp=Q[(p[i]/size)-1];
		for(int j=p[i]/size*size;j<=p[i];j++){
			for(int k:ql[j])tmp[k]=1;
			for(int k:qr[j])tmp[k]=0;
		}
		f[e[p[i]].u-1]|=(f[e[p[i]].v-1]&tmp);
	}
	for(i=0;i<q;i++){
		if(f[h[i].u-1][i])puts("YES");
		else puts("NO");
	}
}
int main(){
	fread(G,1,H,stdin);
	int T=read();
	while(T--)work();
	return 0;
}
posted @ 2022-07-27 10:28  Qzong  阅读(35)  评论(0编辑  收藏  举报