考虑边只有一种权值的简化情况。那么当且仅当两点可以通过边权<=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最小公倍数(莫队+并查集)的更多相关文章

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

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

  2. [HNOI2016]序列(莫队,RMQ)

    [HNOI2016]序列(莫队,RMQ) 洛谷  bzoj 一眼看不出来怎么用数据结构维护 然后还没修改 所以考虑莫队 以$(l,r-1) -> (l,r)$为例 对答案的贡献是$\Sigma_ ...

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

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

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

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

  5. BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]

    4540: [Hnoi2016]序列 题意:询问区间所有子串的最小值的和 不强制在线当然上莫队啦 但是没想出来,因为不知道该维护当前区间的什么信息,维护前后缀最小值的话不好做 想到单调栈求一下,但是对 ...

  6. [BZOJ4540][HNOI2016]序列 莫队

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MB Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n ...

  7. 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈

    [BZOJ4540][Hnoi2016]序列 Description 给定长度为n的序列:a1,a2,…,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,a ...

  8. 【BZOJ4542】[Hnoi2016]大数 莫队

    [BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个 ...

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

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

随机推荐

  1. webpack3构建全面提速优化vue-cli

    前言 伴随着vue的全球化,各种vue的组件框架越来越完善,从早期的element-ui到vux,iview等越来越多高质量的项目,使用vue进行前端构建已然是一件工程化,模块化,敏捷化的事情 在这其 ...

  2. ruby 比较符号==, ===, eql?, equal?

    “==” 最常见的相等性判断 “==” 使用最频繁,它通常用于对象的值相等性(语义相等)判断,在 Object 的方法定义中,“==” 比较两个对象的 object_id 是否一致,通常子类都会重写覆 ...

  3. Excel学习路径总结

    本片涉及从入门到Excel的各个方向,包含众多资料和自己学习的心得,希望您可以仔细阅之:   入门篇: 无论是软件,还是编程,最好的入门就是通过看视频来学习,视频优点为很容易看清楚,手把手教授,不容易 ...

  4. labview初始学习过程中遇到串口读取框红蓝色交替闪烁的处理

           labview工程的程序框图VISA串口读取框红蓝交替闪烁,前面板接收数据错乱,或者是接受不了,这是你不小心设置了断点.

  5. BAT批处理

    常用命令 查看目录内容命令dir 指定可执行文件搜索目录path 创建目录命令md 打开指定目录命令cd 删除当前指定的子目录命令rd 改变当前盘符命令d: 文件复制命令copy 显示文本文件内容命令 ...

  6. LOOP AT SCREEN

    用法 主に.画面の属性を変更させるために使用する. 照会モードでは入力不可とするが入力可能モードでは入力可能とする.ラジオボタンAが選択された場合はラジオボタンBに関連する項目は非表示とするなど.   ...

  7. python eval()函数的妙用和滥用

    eval()函数十分强大,官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果: >>> s='8*8' >>> eval(s) 64 >& ...

  8. 初步学习pg_control文件之十四

    接前文 初步学习pg_control文件之十三 看如下几个: /* * Parameter settings that determine if the WAL can be used for arc ...

  9. 初步学习pg_control文件之十二

    接前问,初步学习pg_control文件之十一,再来看下面这个 XLogRecPtr minRecoveryPoint; 看其注释: * minRecoveryPoint is updated to ...

  10. 【Consul】Consul架构-Session会话

    Consul提供session会话机制--可以用于构建分布式锁,session可以绑定到节点.健康检查.KV数据.目的是提供颗粒锁--受 The Chubby LockService for Loos ...