题意
给你一张图,每条边有两个权值 a,b a , b
每次询问是否存在一个 u→v u → v 的路径,满足 max{a}=A,max{b}=B m a x { a } = A , m a x { b } = B
写在前面
对于这种有两种限制的题目
一般的套路就是条件按照第一种权值为关键字排序,询问按照第二种关键字排序
然后给条件分块,然后对于一个块只把第一关键字符合条件的询问放进去
在把当前块前面的点按照第二关键字排序
这样当前块前面的点都是符合当前询问点对于第一关建字条件的
而且第二关键字都是单调的,所以就可以 two−pointer t w o − p o i n t e r 扫一下
然后对于每个询问,暴力处理一下当前块的贡献
题解
考虑这道题,可以看出只有边权 a≤A,b≤B a ≤ A , b ≤ B 的边才有用
一个简单的想法就是把所有满足条件的边加进去,然后用并查集判断两点是否联通,并且联通块内最大值是否合法
根据上面说的我们可以把边按照 a a 从小到大排序,询问按照从小到大排序
对于一个块 [i,i+Size] [ i , i + S i z e ] 我们把询问的 A A 在之间的询问放进去
然后把 [1,i) [ 1 , i ) 的边按照 b b 从小到大排序,边扫边加边(用并查集维护连通性和最大值)
对于一个询问暴力把 [i,i+Size) [ i , i + S i z e ) 内满足 vala≤A,valb≤B v a l a ≤ A , v a l b ≤ B 的边加进去
然后用并查集判断是否合法
处理完一个询问后再暴力把这些边删掉
所以并查集不能路径压缩,而且还要用一个桶子把这些边都存下(存联通块合并前的状态)
这种写法当
Size=mlogn−−−−−−√
S
i
z
e
=
m
log
n
时最优手玩出来的
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=1e5+5;
typedef int arr[N];
struct eg{
int u,v,a,b,k;
inline void in(){sd(u),sd(v),sd(a),sd(b);}
}a[N],b[N],c[N],d[N];
int n,m,q,Top;arr fa,sz,Am,Bm,ans;
inline bool cpa(const eg a,const eg b){return a.a==b.a?a.b<b.b:a.a<b.a;}
inline bool cpb(const eg a,const eg b){return a.b==b.b?a.a<b.a:a.b<b.b;}
int gf(int x){return fa[x]==x?x:gf(fa[x]);}
inline void merge(int u,int v,int a,int b){
u=gf(u),v=gf(v);if(sz[u]>sz[v])swap(u,v);
d[++Top]={u,v,Am[v],Bm[v],sz[v]};
if(u^v)fa[u]=v,sz[v]+=sz[u],
cmax(Am[v],Am[u]),cmax(Bm[v],Bm[u]);
cmax(Am[v],a),cmax(Bm[v],b);
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(m);
fp(i,1,m)a[i].in();
sd(q);
fp(i,1,q)b[i].in(),b[i].k=i;
sort(a+1,a+m+1,cpa);sort(b+1,b+q+1,cpb);
register int Sz=sqrt(m*log2(n)),i,j,k,l;
for(i=1;i<=m;i+=Sz){
fp(j,1,n)fa[j]=j,Am[j]=Bm[j]=-1,sz[j]=1;
int Sum=0;
fp(j,1,q)if(a[i].a<=b[j].a&&
(b[j].a<a[i+Sz].a||i+Sz>m))c[++Sum]=b[j];
if(!Sum)continue;if(i^1)sort(a+1,a+i,cpb);
for(j=k=1;j<=Sum;++j){
for(;k<i&&a[k].b<=c[j].b;++k)
merge(a[k].u,a[k].v,a[k].a,a[k].b);
Top=0;
for(l=i;l<i+Sz&&l<=m;++l)
if(a[l].a<=c[j].a&&a[l].b<=c[j].b)
merge(a[l].u,a[l].v,a[l].a,a[l].b);
int u=gf(c[j].u),v=gf(c[j].v);
ans[c[j].k]=(u==v&&Am[u]==c[j].a&&Bm[u]==c[j].b);
fd(l,Top,1){
u=d[l].u,v=d[l].v;fa[u]=u;
Am[v]=d[l].a,Bm[v]=d[l].b,sz[v]=d[l].k;
}Top=0;
}
}
fp(i,1,q)puts(ans[i]?"Yes":"No");
return 0;
}