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 }
View Code
posted @ 2018-02-09 15:46  jack_yyc  阅读(171)  评论(0编辑  收藏  举报