【BZOJ4537】[Hnoi2016]最小公倍数

Description

  给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值。所有权值都可以分解成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,那么称路径为简单路径。

Input

  输入文件的第一行包含两个整数N和M,分别代表图的顶点数和边数。接下来M行,每行包含四个整数u、v、a、b代表一条顶点u和v之间、权值为2^a*3^b的边。接下来一行包含一个整数q,代表询问数。接下来q行,每行包含四个整数u、v、a和b,代表一次询问。询问内容请参见问题描述。1<=n,q<=50000、1<=m<=100000、0<=a,b<=10^9

Output

  对于每次询问,如果存在满足条件的路径,则输出一行Yes,否则输出一行 No(注意:第一个字母大写,其余字母小写) 。

Sample Input

4 5
1 2 1 3
1 3 1 2
1 4 2 1
2 4 3 2
3 4 2 2
5
1 4 3 3
4 2 2 3
1 3 2 2
2 3 2 2
1 3 4 4

Sample Output

Yes
Yes
Yes
No
No

题解:最小公倍数=2^a*3^b等价于存在一个连通块使得边权的2的次数最大值=a且3的次数最大值=b,先给出一种暴力方法:

将所有边和询问按a从小到大排序,然后对于每个询问,将a不超过它的所有边按b排序,然后从小到大扔到并查集中,并用并查集维护连通块中b的最大值,如果最后b的最大值=询问的最大值,则输出Yes。

如何优化这个过程呢?考虑按a分块,先将所有询问按(a值所在块-1)排序,然后我们处理第i块中的询问。先将前i块的所有边以及询问按b排序,然后一个一个处理询问和连边。但问题是,对当前询问产生贡献的某些边可能在第i+1块中,但是这些边不超过sqrt(n)个,于是用按秩合并的并查集暴力加入再暴力还原即可。(我写的是按siz合并)。

#include <iostream>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=50010;
int n,m,Q,B,ltp,tp,tq,ltq,top;
struct edge
{
int a,b,A,B,org;
}p[maxn<<1],q[maxn];
int ans[maxn],f[maxn],sz[maxn],sa[maxn],sb[maxn],px[maxn],psa[maxn],psb[maxn],psz[maxn],pf[maxn],vis[maxn];
bool cmpa(const edge &a,const edge &b)
{
return (a.A==b.A)?(a.B<b.B):(a.A<b.A);
}
bool cmpb(const edge &a,const edge &b)
{
return (a.B==b.B)?(a.A<b.A):(a.B<b.B);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int find(int x)
{
return (f[x]==x)?x:find(f[x]);
}
void link(int x)
{
int a=find(p[x].a),b=find(p[x].b);
if(a==b)
{
sa[a]=max(sa[a],p[x].A),sb[a]=max(sb[a],p[x].B);
return ;
}
if(sz[a]<sz[b]) swap(a,b);
f[b]=f[a],sz[a]+=sz[b],sa[a]=max(sa[a],max(sa[b],p[x].A)),sb[a]=max(sb[a],max(sb[b],p[x].B));
}
void add(int x)
{
if(!vis[x]) vis[x]=1,px[++top]=x;
}
int main()
{
n=rd(),m=rd(),B=int(sqrt(double(m)));
int i,j,k,l,ra,rb;
for(i=1;i<=m;i++) p[i].a=rd(),p[i].b=rd(),p[i].A=rd(),p[i].B=rd();
sort(p+1,p+m+1,cmpa);
Q=rd();
for(i=1;i<=Q;i++) q[i].a=rd(),q[i].b=rd(),q[i].A=rd(),q[i].B=rd(),q[i].org=i;
sort(q+1,q+Q+1,cmpa);
p[0].A=p[0].B=-1,p[m+1].A=p[m+1].B=1<<30;
for(i=0;i<=m;ltq=tq,i=tp+B)
{
tp=min(i,m);
for(;tq<Q&&q[tq+1].A>=p[tp].A&&q[tq+1].A<p[min(tp+B,m+1)].A;tq++);
sort(p+1,p+tp+1,cmpb),sort(q+ltq+1,q+tq+1,cmpb);
for(j=1;j<=n;j++) f[j]=j,sa[j]=sb[j]=-1,sz[j]=1;
for(l=1,j=ltq+1;j<=tq;j++)
{
for(;l<=tp&&p[l].B<=q[j].B;link(l++));
top=0;
for(k=tp+1;p[k].A<=q[j].A;k++) if(p[k].B<=q[j].B)
ra=find(p[k].a),rb=find(p[k].b),add(ra),add(rb);
for(k=1;k<=top;k++) psa[k]=sa[px[k]],psb[k]=sb[px[k]],psz[k]=sz[px[k]];
for(k=tp+1;p[k].A<=q[j].A;k++) if(p[k].B<=q[j].B) link(k);
ra=find(q[j].a),rb=find(q[j].b);
if(ra==rb&&sa[ra]==q[j].A&&sb[ra]==q[j].B) ans[q[j].org]=1;
for(k=1;k<=top;k++) f[px[k]]=px[k],sa[px[k]]=psa[k],sb[px[k]]=psb[k],sz[px[k]]=psz[k],vis[px[k]]=0;
}
}
for(i=1;i<=Q;i++)
{
if(ans[i]) printf("Yes\n");
else printf("No\n");
}
return 0;
}//
 

【BZOJ4537】[Hnoi2016]最小公倍数 分块的更多相关文章

  1. [BZOJ4537][HNOI2016]最小公倍数(分块+并查集)

    4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1687  Solved: 607[Submit][Stat ...

  2. [BZOJ4537][Hnoi2016]最小公倍数 奇怪的分块+可撤销并查集

    4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1474  Solved: 521[Submit][Stat ...

  3. BZOJ4537 HNOI2016最小公倍数(莫队+并查集)

    考虑边只有一种权值的简化情况.那么当且仅当两点可以通过边权<=x的边连通,且连通块内最大边权为x时,两点间存在路径max为x的路径.可以发现两种权值是类似的,当且仅当两点可以通过边权1<= ...

  4. 洛谷P3247 [HNOI2016]最小公倍数(分块 带撤销加权并查集)

    题意 题目链接 给出一张带权无向图,每次询问\((u, v)\)之间是否存在一条路径满足\(max(a) = A, max(b) = B\) Sol 这题居然是分块..想不到想不到..做这题的心路历程 ...

  5. 洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]

    洛谷 思路 显然,为了达到这个最小公倍数,只能走\(a,b\)不是很大的边. 即,当前询问的是\(A,B\),那么我们只能走\(a\leq A,b\leq B\)的边. 然而,为了达到这最小公倍数,又 ...

  6. bzoj 4537: [Hnoi2016]最小公倍数 分块+并查集

    题目大意: 给定一张n个点m条边的无向图,每条边有两种权.每次询问某两个点之间是否存在一条路径上的边的两种权的最大值分别等于给定值. n,q <= 50000. m <= 100000 题 ...

  7. BZOJ4537 : [Hnoi2016]最小公倍数

    将边按$a$从小到大排序,每$\sqrt{m}$个取一个关键点. 对于每个关键点,将这个点之前的边以及要在这个关键点回答的询问按$b$排序. 依次加入这个关键点之前的每条边,用并查集维护每个连通块$a ...

  8. BZOJ 4537: [Hnoi2016]最小公倍数 [偏序关系 分块]

    4537: [Hnoi2016]最小公倍数 题意:一张边权无向图,多组询问u和v之间有没有一条a最大为a',b最大为b'的路径(不一定是简单路径) 首先想到暴力做法,题目要求就是判断u和v连通,并查集 ...

  9. 【LG3247】[HNOI2016]最小公倍数

    [LG3247][HNOI2016]最小公倍数 题面 洛谷 题解 50pts 因为拼凑起来的部分分比较多,所以就放一起了. 以下设询问的\(a,b\)为\(A,B\), 复杂度\(O(nm)\)的:将 ...

随机推荐

  1. IP分类:A,B,C,D,E五类

    IP地址分为五类: IP地址分为五类:A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用于组播,E类用于实验. 常用的三类IP地址 IP = 网路地址(网络号)+主机地址(主 ...

  2. 查看Linux服务器CPU使用率、内存使用率、磁盘空间占用率、负载情况

    [root@server script]# vi monitor.py #!/usr/bin/env python # -*- coding:utf-8 -*- #Author: nulige imp ...

  3. 新人补钙系列教程之:Molehill底层API中最重要的Context3D

    Context3D,是一个三维空间的处理环境,负责创建并处理三维对象的各个要素如顶点.片段.透视等等,并将处理的结果使用AGAL(Adobe图形汇编语言)上传给显卡进行运算,运算结果最终被回传给CPU ...

  4. 清理memcached缓存

    清理memcached缓存 学习了:https://blog.csdn.net/allus0918/article/details/50481927 使用telnet登录 flush_all 命令:

  5. 转:myeclipse和eclipse的区别和联系,以及版本间的对应关系

    myeclipse和eclipse的区别和联系,以及版本间的对应关系 Eclipse:IBM花了4千万美金来开发这个IDE(Integrated Development Environment).第一 ...

  6. Android经常使用UI组件 - Button

    button(Button)是Android其中一个经常使用的UI组件.非常小可是在开发中最经常使用到.一般通过与监听器结合使用.从而触发一些特定事件. Button继承了TextView.它的功能就 ...

  7. 怎么运行Typescript

    依据官方示例: npm i -g typescript 示例:tsc *.ts 实例:tsc hello.ts 不过以上实现的太有限制了,如下实现可满足正常测试以及学习使用 package,json ...

  8. redis有序集合的一个应用

    一.需求 记录用户uid和上次操作时间;并清除5分钟以前的数据.用redis的一个key实现.本打算用hash,但hash类型在过期5分钟以前的数据时颇为麻烦. 二.代码实现 class LastLo ...

  9. react-native-router-flux 页面跳转与传值

    1.正向跳转假设情景:从Home页跳转到Profile页面,Profile场景的key值为profile 不带参数: Actions.profile 带参数: Actions.profile({'ke ...

  10. SDUT 2766-小明传奇2(母函数)

    小明传奇2 nid=24#time" title="C.C++.go.haskell.lua.pascal Time Limit1000ms Memory Limit 65536K ...