一开始看错题目 以为求的是最大公因数QWQ然后一直看不懂Claris的题解= =
传送门:
http://www.cnblogs.com/clrs97/p/5406018.html
对于边集分块然后每次加上去就好了
好神!
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
char c;
inline void read(int &a)
{a=0;do c=getchar();while(c<'0'||c>'9');while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();}
struct Q{int op,a,Old,opp;};//1 Oldf 2 Olda 3 Oldb 4 Oldrank
Q Stack[100001];
int tot;
int f[100001];
int fb[100001],fa[100001],rank[100001];
int find(int x){return x==f[x]?x:find(f[x]);}
inline void Merge(int u,int v,int a,int b)
{
u=find(u),v=find(v);
if(u!=v)
{
if(rank[u]<rank[v])swap(u,v);
if(rank[u]==rank[v])Stack[++tot]=(Q){4,a,rank[u],u},rank[u]++;
Stack[++tot]=(Q){1,a,f[v],v};
f[v]=u;
}
int fl=max(a,fa[v]);
if(fl>fa[u])
Stack[++tot]=(Q){2,u,fa[u],u},fa[u]=fl;
fl=max(b,fb[v]);
if(fl>fb[u])
Stack[++tot]=(Q){3,u,fb[u],u},fb[u]=fl;
}
inline void Return(int A)
{
for(tot;tot&&Stack[tot].a>A;tot--)
{
if(Stack[tot].op==1)f[Stack[tot].opp]=Stack[tot].Old;
if(Stack[tot].op==2)fa[Stack[tot].opp]=Stack[tot].Old;
if(Stack[tot].op==3)fb[Stack[tot].opp]=Stack[tot].Old;
if(Stack[tot].op==4)rank[Stack[tot].opp]=Stack[tot].Old;
}
}
struct Query{int a,b,u,v,no,ans;};
Query Ques[100001];
Query Side[100001];
Query Cache[100001];
int Ans[100001];
inline bool cmpQue(Query a,Query b){return a.a<b.a;}
inline bool cmpQue2(Query a,Query b){return a.b<b.b;}
int n,m;
int cnt;
int main()
{
read(n),read(m);
for(int i=1;i<=m;i++)read(Side[i].u),read(Side[i].v),read(Side[i].a),read(Side[i].b);
int q;
read(q);
for(int i=1;i<=q;i++)read(Ques[i].u),read(Ques[i].v),read(Ques[i].a),read(Ques[i].b),Ques[i].no=i;
int Size=sqrt(m)+1;
sort(Side+1,Side+1+m,cmpQue);
for(int i=0;i<=m;i+=Size)
{
tot=0;
cnt=0;
for(int j=1;j<=q;j++)
if(Ques[j].a>=Side[i].a&&(i+Size>m||Ques[j].a<Side[i+Size].a))
Cache[++cnt]=Ques[j];
if(!cnt)continue;
sort(Side+1,Side+1+i,cmpQue2);
sort(Cache+1,Cache+1+cnt,cmpQue2);
for(int j=1;j<=n;j++)f[j]=j,fa[j]=fb[j]=-1,rank[j]=1;
for(int j=1,k=1;j<=cnt;j++)
{
while(k<=i&&Side[k].b<=Cache[j].b)Merge(Side[k].u,Side[k].v,Side[k].a,Side[k].b),k++;
tot=0;
for(int t=i+1;t<=min(i+Size,m);t++)
if(Side[t].a<=Cache[j].a&&Side[t].b<=Cache[j].b)Merge(Side[t].u,Side[t].v,Side[t].a,Side[t].b);
int tp;
Cache[j].ans=((tp=find(Cache[j].u))==find(Cache[j].v)&&fa[tp]==Cache[j].a&&fb[tp]==Cache[j].b);
Return(0);
}
for(int j=1;j<=cnt;j++)Ans[Cache[j].no]=Cache[j].ans;
}
for(int i=1;i<=q;i++)puts(Ans[i]?"Yes":"No");
return 0;
}