【bzoj4537】 Hnoi2016—最小公倍数
http://www.lydsy.com/JudgeOnline/problem.php?id=4537 (题目链接)
题意
给出一个${n}$个点${m}$条边的无向图,每条边有两个权值${a,b}$。给出$Q$个询问,问$u,v$两点间是否存在一条路径(可以不是简单路径),使得路径上的边的最大$a,b$正好等于$A,B$。
Solution
http://blog.csdn.net/zmh964685331/article/details/51194393
我们考虑按照$a$的权值分块。每次找到$a$的权值在块内的询问,对它们进行处理。
将这些询问按照$b$的大小排序以后,我们用并查集维护图的连通性。此时的边有两类,第一类就是在之前的块中的边,这些边的$a$肯定是小于询问的$a$的,我们将这些边按照$b$排序,然后依次加入。第二类就是在当前块中的边,这些边我们不好处理,直接暴for过去,如果它们的$a,b$都小于询问的$a,b$,就加入到图中,做完之后再将这些边暴力还原,因为只有$\sqrt{m}$条,所以不虚。
并查集按秩合并,同时维护连通块中$a,b$的最值。查询的时候就是判断是否$u,v$在同一连通块中,这个连通块$a,b$的最大值是否正好等于询问的$a,b$。
细节
块的大小,开大一点,不然会TLE。
如果大块大块相同的$a$,我们的询问会被重复不断的加入,这是很浪费的,所以我们对这种情况进行一些处理。
bzoj是有多慢,本机20s,交上去几乎要TLE。。。
代码
// bzoj4537
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf (1ll<<30)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
inline int gi() {
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=100010;
int ans[maxn],Q,n,m,top,tot,S;
int fa[maxn],da[maxn],db[maxn],size[maxn];
struct option {int u,v,da,db,fa,size;}op[maxn];
struct data {int u,v,a,b,id;}e[maxn],q[maxn],tmp[maxn]; inline bool cmpa(data a,data b) {return a.a==b.a ? a.b<b.b : a.a<b.a;}
inline bool cmpb(data a,data b) {return a.b==b.b ? a.a<b.a : a.b<b.b;} inline int find(int x) {
return fa[x]==x ? x : find(fa[x]);
}
inline void Union(int u,int v,int a,int b) {
u=find(u),v=find(v);
if (size[u]>size[v]) swap(u,v);
op[++tot]=(option){u,v,da[v],db[v],fa[u],size[v]};
if (u==v) da[v]=max(da[v],a),db[v]=max(db[v],b);
else {
fa[u]=v;size[v]+=size[u];
da[v]=max(da[v],max(da[u],a));
db[v]=max(db[v],max(db[u],b));
}
}
int main() {
n=gi(),m=gi();
for (int i=1;i<=m;i++) e[i].u=gi(),e[i].v=gi(),e[i].a=gi(),e[i].b=gi(),e[i].id=i;
S=(int)sqrt(3*m);
Q=gi();
for (int i=1;i<=Q;i++) q[i].u=gi(),q[i].v=gi(),q[i].a=gi(),q[i].b=gi(),q[i].id=i;
sort(e+1,e+1+m,cmpa);
sort(q+1,q+1+Q,cmpb);
for (int i=1;i<=m;i+=S) {
int L=i,R=min(i+S-1,m);
top=0;
for (int j=1;j<=Q;j++)
if (q[j].a>=e[L].a && (R==m || q[j].a<e[R+1].a)) tmp[++top]=q[j]; //考虑很多边a相等的情况
sort(e+1,e+L,cmpb);
for (int j=1;j<=n;j++) fa[j]=j,size[j]=1,da[j]=db[j]=-1;
for (int j=1,k=1;j<=top;j++) {
for (;k<L && e[k].b<=tmp[j].b;k++) Union(e[k].u,e[k].v,e[k].a,e[k].b);
tot=0;
for (int l=L;l<=R;l++)
if (e[l].a<=tmp[j].a && e[l].b<=tmp[j].b) Union(e[l].u,e[l].v,e[l].a,e[l].b);
int u=find(tmp[j].u),v=find(tmp[j].v);
ans[tmp[j].id]= u==v && da[u]==tmp[j].a && db[u]==tmp[j].b;
for (;tot;tot--) {
fa[op[tot].u]=op[tot].fa;
db[op[tot].v]=op[tot].db;
da[op[tot].v]=op[tot].da;
size[op[tot].v]=op[tot].size;
}
}
}
for (int i=1;i<=Q;i++) printf(ans[i] ? "Yes\n" : "No\n");
return 0;
}
【bzoj4537】 Hnoi2016—最小公倍数的更多相关文章
- [BZOJ4537][HNOI2016]最小公倍数(分块+并查集)
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1687 Solved: 607[Submit][Stat ...
- [BZOJ4537][Hnoi2016]最小公倍数 奇怪的分块+可撤销并查集
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1474 Solved: 521[Submit][Stat ...
- BZOJ4537 HNOI2016最小公倍数(莫队+并查集)
考虑边只有一种权值的简化情况.那么当且仅当两点可以通过边权<=x的边连通,且连通块内最大边权为x时,两点间存在路径max为x的路径.可以发现两种权值是类似的,当且仅当两点可以通过边权1<= ...
- BZOJ4537 : [Hnoi2016]最小公倍数
将边按$a$从小到大排序,每$\sqrt{m}$个取一个关键点. 对于每个关键点,将这个点之前的边以及要在这个关键点回答的询问按$b$排序. 依次加入这个关键点之前的每条边,用并查集维护每个连通块$a ...
- 【BZOJ4537】[Hnoi2016]最小公倍数 分块
[BZOJ4537][Hnoi2016]最小公倍数 Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在 ...
- BZOJ 4537: [Hnoi2016]最小公倍数 [偏序关系 分块]
4537: [Hnoi2016]最小公倍数 题意:一张边权无向图,多组询问u和v之间有没有一条a最大为a',b最大为b'的路径(不一定是简单路径) 首先想到暴力做法,题目要求就是判断u和v连通,并查集 ...
- 【LG3247】[HNOI2016]最小公倍数
[LG3247][HNOI2016]最小公倍数 题面 洛谷 题解 50pts 因为拼凑起来的部分分比较多,所以就放一起了. 以下设询问的\(a,b\)为\(A,B\), 复杂度\(O(nm)\)的:将 ...
- 【 bzoj4537】HNOI2016 最小公倍数
首先将边按a的值分组,每$\sqrt{m}$一组. 对于每一组,将符合一组a的询问选出来,将这些询问和这一块之前的边(a一定小于这些询问)按b排序,然后交替插入,询问,对于一个询问,在当前块也有可能有 ...
- 4537: [Hnoi2016]最小公倍数
Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在有q个询问,每次询问给定四个参数u.v.a和b,请你 ...
随机推荐
- Android Studio com.android.support:percent 导入错误 - 转
看第一行代码(第二版的)书,讲了一个关于PercentFrameLayout和PercentRelativeLayout的部分,书上在build.gradle中导入了com.android.suppo ...
- 大数据入门第二十二天——spark(三)自定义分区、排序与查找
一.自定义分区 1.概述 默认的是Hash的分区策略,这点和Hadoop是类似的,具体的分区介绍,参见:https://blog.csdn.net/high2011/article/details/6 ...
- Android漏洞——将Android恶意代码隐藏在图片中
研究人员发现了Android上又一个严重的安全漏洞:将Android恶意代码隐藏在图片中(Hide Android Applications in Images). 在该漏洞向外界公开之前,Googl ...
- navicat 创建查询失败 can not create file
数据库连接很正常, 却无法创建查询, 不知道啥毛病 竟然是存储路径问题,点开连接属性,修改高级里面的保存路径,删掉“:3308”, OK了.冒号是个windows保留的盘符,应该就是这个原因
- web api token验证理解
最近一直在学习web api authentication,以Jwt为例,可以这样理解,token是身份证,用户名和密码是户口本,身份证是有有效期的(jwt 有过期时间),且携带方便(自己带有所有信息 ...
- Js_图片轮播
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- 阿里云配置ssl证书
一.申请证书和下载证书(阿里云申请) 二.在nginx服务器上配置ssl证书 1.检查服务器是否安装openssl 2.在nginx conf 文件夹创建 cret 文件,放置证书 [root@web ...
- OpenStack与OpenDaylight的对接过程
由于项目中需要使用OpenDaylight(Oxygen)替换OpenStack(Otaca)中的neutron-openvswitch-agent,能找到的一些资料都是比较旧的版本,官网上的文档也一 ...
- 使用阿里云Python SDK管理ECS安全组
准备工作 本机操作系统:CentOS7 python版本:python2.7.5 还需要准备如下信息: 一个云账号.Access Key ID.Access Key Secret.安全组ID.Regi ...
- Python_汇总生成统计报表
import xlrd import xlwt from xlutils.copy import copy objWb = xlrd.open_workbook(r'C:\Users\IBM\Desk ...