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 ...
随机推荐
- 使用Python第三方库生成二维码
本文主要介绍两个可用于生成二维码的Python第三方库:MyQR和qrcode. MyQR的使用: 安装: pip install MyQR 导入: from MyQR import myqr imp ...
- H5混合开发进阶
混合开发: 原生app里面,IOS 安卓的原生app里面,嵌套h5界面. 通过原生app里的一个webView盒子进行交互.webView是原生app内置的一个XXX,里面可以放置h5界面.可以相互调 ...
- Java实现文件的上传下载
文件上传,下载的方法: 上传代码 /** * 文件上传.保存 * * @param mapping * @param form * @param request * @param response * ...
- c#winform使用WebBrowser 大全
C# WinForm WebBrowser (一) MSDN资料 1.主要用途:使用户可以在窗体中导航网页. 2.注意:WebBrowser 控件会占用大量资源.使用完该控件后一定要调用 Dispos ...
- 【tp5.1】composer安装PHPExcel以及导入\导出Excel
一.安装PHPExcel 1.下载:PHPExcel https://github.com/PHPOffice/PHPExcel 2.解压后:Classes文件夹改名为PHPExcel 3.把文件夹 ...
- 微信小程序缓存
购物车数据加入缓存,相同的商品值修改数量,然后再次加入缓存中 修改购物车的数据的时候同理,都是修改缓存数据然后加入到缓存中. 具体的使用方法看官方文档,我只是提供思路
- ko绑定----记录
1.绑定变量 globalData = ko.observable({item:{}}); 2.绑定html ko.applyBindings(globalData, document.getElem ...
- C语言实例解析精粹学习笔记——30
实例30: 用已知字符串s中的字符,生成由其中n个字符组成的所有字符排列.设n小于字符串s的字符个数,其中s中的字符在每个排列中最多出现一次.例如,对于s[]="abc",n=2, ...
- Verilog学习笔记基本语法篇(七)········ 生成块
生成块可以动态的生成Verilog代码.可以用于对矢量中的多个位进行重复操作.多个模块的实例引用的重复操作.根据参数确定程序中是否包含某段代码.生成语句可以控制变量的声明.任务和函数的调用.还能对实例 ...
- 【转】已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭
在运用Linq to sql 或者 linq to entity等相关linq技术进行数据库访问操作时,如果发生上述异常是因为是因为.NET內部是使用DataReader作数据存取,DataReade ...