bzoj 4537 最小公倍数
给定一张N个顶点M条边的无向图 每条边上带有权值 所有权值都可以分解成2^a*3^b的形式
q个询问,每次询问给定四个参数u、v、a和b,请你求出是否存在一条顶点u到v之间的路径,使得路径依次经过的边上的权值的最小公倍数为2^a*3^b
注意:路径可以不是简单路径
下面是一些可能有用的定义:
最小公倍数:K个数a1,a2,…,ak的最小公倍数是能被每个ai整除的最小正整数
路径:路径P:P1,P2,…,Pk是顶点序列,满足对于任意1<=i<k,节点Pi和Pi+1之间都有边相连
简单路径:如果路径P:P1,P2,…,Pk中,对于任意1<=s≠t<=k都有Ps≠Pt,那么称路径为简单路径
思路:
对于每个询问(u,v,A,B),将a<=A和b<=B的边全部加入并查集中,最后判断u和v是否在同一连通分量中且连通分量包含的最大的a=A,最大的b=B即可
把询问和边离线按a排序,询问时在已经加入的边中按b值排序加入并查集中
结合起来,按a值将询问和边分块,前面的边按第二种做法做,块内的边按第一种做法做就行了
因为并查集需要支持撤销,所以要用按秩合并
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,m,T,fa[MAXN],rnk[MAXN],f,pos,b,mxp[MAXN],mxq[MAXN],top,cnt,size,ans[MAXN]; 21 struct data 22 { 23 int u,v,p,q,pos; 24 bool operator < (const data & a) const {return q<a.q||(q==a.q&&pos<a.pos);} 25 }qs[MAXN],e[MAXN<<1],tmp[MAXN<<2]; 26 struct stck{int u,v,rnk,p,q;}st[MAXN<<1]; 27 int find(int x) {return x==fa[x]?x:find(fa[x]);} 28 void merge(int u,int v,int p,int q) 29 { 30 int x=find(u),y=find(v); 31 if(rnk[x]<rnk[y]) swap(x,y); 32 st[++top]=(stck) {x,y,rnk[x],mxp[x],mxq[x]}; 33 fa[y]=x; 34 mxp[x]=max(p,max(mxp[y],mxp[x])); 35 mxq[x]=max(q,max(mxq[x],mxq[y])); 36 if(rnk[x]==rnk[y]) rnk[x]++; 37 } 38 bool Cmp(data a,data b) {return a.p<b.p||(a.p==b.p&&a.q<b.q);} 39 void dlt() 40 { 41 fa[st[top].v]=st[top].v,rnk[st[top].u]=st[top].rnk,mxp[st[top].u]=st[top].p,mxq[st[top].u]=st[top].q,top--; 42 } 43 int main() 44 { 45 //freopen("al.in","r",stdin); 46 //freopen("al.out","w",stdout); 47 n=read(),m=read();int x,y,tot=0; 48 for(int i=1;i<=m;i++) 49 e[i].u=read(),e[i].v=read(),e[i].p=read(),e[i].q=read(),e[i].pos=0; 50 size=sqrt(m*2); 51 sort(e+1,e+m+1,Cmp); 52 T=read(); 53 for(int i=1;i<=T;i++) 54 qs[i].u=read(),qs[i].v=read(),qs[i].p=read(),qs[i].q=read(),qs[i].pos=i; 55 sort(qs+1,qs+T+1,Cmp); 56 for(int i=1;i<=m;i++) 57 { 58 if((++tot==size)||i==m) 59 { 60 cnt=0; 61 for(int j=1;j<=i-tot;j++) tmp[++cnt]=e[j]; 62 for(int j=1;j<=T;j++) 63 if(qs[j].p>=e[i-cnt+1].p&&(i==m||qs[j].p<e[i+1].p)) tmp[++cnt]=qs[j]; 64 if(i-tot!=cnt) 65 { 66 for(int j=1;j<=n;j++) fa[j]=j,rnk[j]=0,mxp[j]=mxq[j]=-1; 67 sort(tmp+1,tmp+cnt+1);top=0; 68 for(int j=1;j<=cnt;j++) 69 { 70 if(tmp[j].pos) 71 { 72 for(int k=i-tot+1;k<=i+1;k++) 73 { 74 if(e[k].p>tmp[j].p||k>i) 75 { 76 int x=find(tmp[j].u),y=find(tmp[j].v); 77 if(x==y&&mxp[x]==tmp[j].p&&mxq[x]==tmp[j].q) ans[tmp[j].pos]=1; 78 for(int l=i-tot+1;l<=k-1;l++) if(e[l].q<=tmp[j].q) dlt(); 79 break; 80 } 81 if(e[k].q<=tmp[j].q) merge(e[k].u,e[k].v,e[k].p,e[k].q); 82 } 83 } 84 else merge(tmp[j].u,tmp[j].v,tmp[j].p,tmp[j].q); 85 } 86 } 87 tot=0; 88 } 89 } 90 for(int i=1;i<=T;i++) 91 puts(ans[i]?"Yes":"No"); 92 }