BZOJ4537 HNOI2016最小公倍数(莫队+并查集)
考虑边只有一种权值的简化情况。那么当且仅当两点可以通过边权<=x的边连通,且连通块内最大边权为x时,两点间存在路径max为x的路径。可以发现两种权值是类似的,当且仅当两点可以通过边权1<=x且边权2<=y的边连通,且连通块内最大边权1为x、最大边权2为y时,两点间存在路径max为(x,y)的路径。
一种权值的情况很好处理,从小到大加边并查集维护即可。观察数据范围容易想到根号算法。考虑类似回滚莫队的做法。按边权1将边分块,块内按边权2排序。处理某块时将所有权值1恰好小于该块max的询问找出来按边权2排序,依次处理,每次加入之前块中边权2不大于它的边,然后在块内暴力找满足条件的边加入,使用带撤销并查集即可维护。
注意存在u=v,a=b=0的询问,所以集合内权值最大值的初值不能设成0。
调了半天以为有什么细节问题,结果发现并查集整个写错了,居然luogu还有80分数据水爆了啊。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 50010
#define M 100010
#define inf 1000000000
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int n,m,q,t,L[N],R[N],fa[N],mx[N],mxa[N],mxb[N],ans[N],cur[N],size[N],cnt;
int top;
struct data
{
int x,y,a,b,k,i;
bool operator <(const data&t) const
{
return k<t.k||k==t.k&&b<t.b;
}
}e[M],a[N],undo[N];
int find(int x){return fa[x]==x?x:find(fa[x]);}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4537.in","r",stdin);
freopen("bzoj4537.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
int block=sqrt(m);
for (int i=;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read(),e[i].k=e[i].a;
sort(e+,e+m+);
for (int i=;i<=m;i++)
{
e[i].k=(i-)/block,mx[(i-)/block]=max(mx[(i-)/block],e[i].a),R[(i-)/block]=max(R[(i-)/block],i);
if ((i-)%block==) L[(i-)/block]=i;
}
cnt=(m-)/block+;mx[cnt]=inf+;R[cnt]=-;
sort(e+,e+m+);
q=read();
for (int i=;i<=q;i++)
{
a[i].x=read(),a[i].y=read(),a[i].a=read(),a[i].b=read(),a[i].i=i;
for (int j=;j<=cnt;j++) if (a[i].a<mx[j]) {a[i].k=j;break;}
}
sort(a+,a+q+);
int x=;
for (int i=;i<=cnt;i++)
{
for (int i=;i<=n;i++) fa[i]=i,size[i]=;
memset(mxa,,sizeof(mxa));
memset(mxb,,sizeof(mxb));
for (int j=;j<i;j++) cur[j]=L[j]-;
while (x<q&&a[x+].k==i)
{
x++;
for (int j=;j<i;j++)
while (e[cur[j]+].k==j&&e[cur[j]+].b<=a[x].b)
{
cur[j]++;
int p=find(e[cur[j]].x),q=find(e[cur[j]].y);
if (size[p]<size[q]) swap(p,q);
if (p!=q) size[p]+=size[q];
fa[q]=p;mxa[p]=max(max(mxa[p],mxa[q]),e[cur[j]].a),mxb[p]=max(max(mxb[p],mxb[q]),e[cur[j]].b);
}
int top=;
for (int j=L[i];j<=R[i];j++)
{
if (e[j].b>a[x].b) break;
if (e[j].a<=a[x].a)
{
int p=find(e[j].x),q=find(e[j].y);
if (size[p]<size[q]) swap(p,q),swap(e[j].x,e[j].y);
top++;undo[top].x=q,undo[top].i=size[p];
undo[top].y=p,undo[top].a=mxa[p],undo[top].b=mxb[p];
if (p!=q) size[p]+=size[q];
fa[q]=p;mxa[p]=max(max(mxa[p],mxa[q]),e[j].a),mxb[p]=max(max(mxb[p],mxb[q]),e[j].b);
}
}
if (find(a[x].x)==find(a[x].y)&&mxa[find(a[x].x)]==a[x].a&&mxb[find(a[x].x)]==a[x].b) ans[a[x].i]=;
for (;top;top--)
{
mxa[undo[top].y]=undo[top].a,mxb[undo[top].y]=undo[top].b;
fa[undo[top].x]=undo[top].x;size[undo[top].y]=undo[top].i;
}
}
}
for (int i=;i<=q;i++) printf(ans[i]?"Yes\n":"No\n");
return ;
}
BZOJ4537 HNOI2016最小公倍数(莫队+并查集)的更多相关文章
- 洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]
洛谷 思路 显然,为了达到这个最小公倍数,只能走\(a,b\)不是很大的边. 即,当前询问的是\(A,B\),那么我们只能走\(a\leq A,b\leq B\)的边. 然而,为了达到这最小公倍数,又 ...
- [HNOI2016]序列(莫队,RMQ)
[HNOI2016]序列(莫队,RMQ) 洛谷 bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...
- [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 ...
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...
- [BZOJ4540][HNOI2016]序列 莫队
4540: [Hnoi2016]序列 Time Limit: 20 Sec Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...
- 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈
[BZOJ4540][Hnoi2016]序列 Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,a ...
- 【BZOJ4542】[Hnoi2016]大数 莫队
[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...
- BZOJ4537 : [Hnoi2016]最小公倍数
将边按$a$从小到大排序,每$\sqrt{m}$个取一个关键点. 对于每个关键点,将这个点之前的边以及要在这个关键点回答的询问按$b$排序. 依次加入这个关键点之前的每条边,用并查集维护每个连通块$a ...
随机推荐
- centos7-mongodb3.4.6集群的搭建
0.需要环境 安装包:mongodb-linux-x86_64-3.4.6.tgz 安装路径:/usr/mongodb 服务器: 192.168.177.131/132/133 mongos 2000 ...
- JavaScript--文本框中只允许输入数字的操作(其他字符不显示)
在web网页中,尤其是某些提交表单操作,需要验证文本框输入内容,本文利用文本框键盘事件和事件对象,对文本框只允许输入数字方法进行总结. 1.键盘事件 keydown ---->键盘按下事件 ...
- typecho博客组插件:openSug.js百度搜索框下拉提示免费代码
Typecho候选搜索增强插件:安装openSug插件即可获得带有“搜索框提示”功能的搜索框,让Typecho搜索更便捷! 支持百度.谷歌.雅虎.Yandex.360好搜.UC神马.酷狗.优酷.淘 ...
- 微信小程序中无刷新修改
1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...
- 源码安装CentOs7下的PHP7
首先安装APACHE环境,直接用yum安装 yum install httpd httpd-devel /etc/httpd/ systemctl start httpd.service #启动apa ...
- Hadoop(20)-MapReduce框架原理-OutputFormat
1.outputFormat接口实现类 2.自定义outputFormat 步骤: 1). 定义一个类继承FileOutputFormat 2). 定义一个类继承RecordWrite,重写write ...
- 二、Django需要的知识点
1.请求(request): 客户端到服务器端. 响应(response):服务器端到客户端. HTTP/1.1 协议共定义了 8 种请求方式,分别是: OPTIONS. HEAD. GET. POS ...
- Leecode刷题之旅-C语言/python-26.删除数组中的重复项
/* * @lc app=leetcode.cn id=26 lang=c * * [26] 删除排序数组中的重复项 * * https://leetcode-cn.com/problems/remo ...
- 清华大学《C++语言程序设计基础》线上课程笔记01---基础概念与一些注意事项
使用除法的注意事项 double b = 4.0 * 1/239.0; 因为整数相除结果取整,如果参数写1/239,结果就都是0 浮点数注意事项 浮点数是近似存储,所以不能直接比较两个浮点数的大小, ...
- [Cracking the Coding Interview] 4.5 Validate BST
Implement a function to check if a binary tree is a binary search tree. 这道题很经典,让我们判断一棵树是不是二叉查找树.但是首先 ...