洛谷


思路

显然,为了达到这个最小公倍数,只能走\(a,b\)不是很大的边。

即,当前询问的是\(A,B\),那么我们只能走\(a\leq A,b\leq B\)的边。

然而,为了达到这最小公倍数,又需要有\(\max\{a\}=A,\max\{b\}=B\)。

那么暴力做法就很显然了:并查集维护连通块的\(\max\{a\},\max\{b\}\),询问时把满足条件的边全都连上,看最终是否满足条件。

如何优化呢?

把边按\(a\)排序,撒\(\sqrt m\)个关键点,每个关键点把它前面的边按\(b\)排序。

每个询问找出\(a\leq A\)的最靠右关键点,把这个询问放进去。

每个关键点把询问按\(B\)排序。

在关键点回答询问时维护一个从左到右的指针。由于询问的\(B\)递增,指针可以一直从左往右扫。

然后把这个关键点到下一个关键点之间满足条件的边加进去,得到答案,再撤回。

假设\(n,m,q\)同阶(虽然实际上不同阶),则复杂度\(O(n\sqrt n\log n)​\),可能可以调整块大小得到更优的复杂度。


代码

注意\(a,b\)有0,一开始最大值要赋为-1。

由于使用了较多STL,需要开O2

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 101010
#define S 350
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template<typename T>inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
inline bool chkmax(int &x,int y){return x<y?x=y,1:0;}
template<typename T>inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; int n,m,Q;
struct hh{int u,v,a,b;}edge[sz];
inline bool cmp1(const hh &x,const hh &y){return x.a<y.a;}
inline bool cmp2(const hh &x,const hh &y){return x.b<y.b;}
bool ans[sz]; struct Query{int u,v,a,b,id;};
inline bool cmp(const Query &x,const Query &y){return x.b<y.b;}
int blo,num,val[S],pos[S];
vector<hh>v[S];
vector<Query>q[S];
void init()
{
chktime();
sort(edge+1,edge+m+1,cmp1);
blo=sqrt(m);num=m/blo+(bool)(m%blo);
rep(i,1,num) val[i]=edge[pos[i]=i*blo-blo].a;
chktime();
rep(i,1,num)
{
rep(j,1,pos[i]) v[i].push_back(edge[j]);
sort(v[i].begin(),v[i].end(),cmp2);
}
pos[num+1]=m+1;
}
int fa[sz],mx1[sz],mx2[sz],dep[sz];
int getfa(int x){return x==fa[x]?x:getfa(fa[x]);}
struct hhh{int x,y,mx1,mx2,d;};
hhh merge(hh e)
{
int x=getfa(e.u),y=getfa(e.v);
if (dep[x]>dep[y]) swap(x,y);
hhh ret=(hhh){x,y,mx1[y],mx2[y],dep[y]};
fa[x]=y;
chkmax(mx1[y],max(mx1[x],e.a));chkmax(mx2[y],max(mx2[x],e.b));
if (dep[x]==dep[y]) ++dep[y];
return ret;
}
inline void del(hhh s){fa[s.x]=s.x;mx1[s.y]=s.mx1;mx2[s.y]=s.mx2;dep[s.y]=s.d;}
void solve(int s)
{
sort(q[s].begin(),q[s].end(),cmp);
rep(i,1,n) fa[i]=i,mx1[i]=mx2[i]=-1,dep[i]=1;
int p=0;
rep(i,0,(int)q[s].size()-1)
{
int aa=q[s][i].a,bb=q[s][i].b;
while (p<=(int)v[s].size()-1&&v[s][p].b<=bb) merge(v[s][p]),++p;
stack<hhh>SS;
rep(j,pos[s]+1,pos[s+1]-1)
if (edge[j].a<=aa&&edge[j].b<=bb)
SS.push(merge(edge[j]));
int uu=getfa(q[s][i].u),vv=getfa(q[s][i].v);
if (uu==vv&&mx1[uu]==aa&&mx2[uu]==bb) ans[q[s][i].id]=1;
while (!SS.empty()) del(SS.top()),SS.pop();
}
} int main()
{
file();
int x,y,a,b;
read(n,m);
rep(i,1,m) read(x,y,a,b),edge[i]=(hh){x,y,a,b};
chktime();
read(Q);
init();
chktime();
rep(i,1,Q)
{
read(x,y,a,b);
int t=upper_bound(val+1,val+num+1,a)-val-1;
q[t].push_back((Query){x,y,a,b,i});
}
chktime();
rep(i,1,num) solve(i);
rep(i,1,Q) puts(ans[i]?"Yes":"No");
chktime();
return 0;
}

洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]的更多相关文章

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

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

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

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

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

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

  4. Bzoj1015/洛谷P1197 [JSOI2008]星球大战(并查集)

    题面 Bzoj 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...

  5. 洛谷1525 关押罪犯NOIP2010 并查集

    问题描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两 ...

  6. 洛谷P1525 关押罪犯(并查集、二分图判定)

    本人蒟蒻,只能靠题解AC,看到大佬们的解题思路,%%%%%% https://www.luogu.org/problemnew/show/P1525 题目描述 S城现有两座监狱,一共关押着N名罪犯,编 ...

  7. 洛谷 P2661 信息传递 Label:并查集||强联通分量

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  8. 洛谷 P1111 修复公路 Label:并查集

    题目背景 A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车.政府派人修复这些公路. 题目描述 给出A地区的村庄数N,和公路数M,公路是双向的.并告诉你每条公路的连着哪两个村庄,并告诉你什么时 ...

  9. 洛谷P3367 【模板】并查集

    P3367 [模板]并查集 293通过 551提交 题目提供者HansBug 标签 难度普及- 提交  讨论  题解 最新讨论 不知道哪错了 为啥通不过最后三个节点 题解 不懂为什么MLE 最后一个数 ...

随机推荐

  1. exec存储过程示例

    假如存储过程为test,两个参数为aa,bb那么有以下两种写法,不要带括号EXEC [dbo].[test] @aa = 111, @bb = 222 exec test 111,222

  2. 【省时的 IDEA 配置 】 JRebel Mybatis Problems Spring Auto-Scan

    在 Java Web 开发中, 一般更新了 Java 文件后要手动重启 Tomcat 服务器, 才能生效, 浪费不少生命啊, 自从有了 JRebel 这神器的出现, 不论是更新 class 类还是更新 ...

  3. nginx默认80端口被System占用,造成nginx启动报错的解决方案

    今天启动window上的nginx总是报错 错误信息是bind() to 0.0.0.0:80 failed (10013: An attempt was made to access a socke ...

  4. 怎样远程访问 MySQL

    比如我在PC上安装有 phpmyadmin, 图形界面很友好,我的MySQL 在一台Centos 7.5服务器上,很自然的想到用phpmyadmin 去登录linux上的MySQL. 但是折腾了很久也 ...

  5. Js JSON.stringify()与JSON.parse()与eval()详解及使用案例

    (1)JSON.parse函数 作用:将json字符串转换成json对象. 语法:JSON. parse(text[,reviver]). 参数:text  必须:一个有效的json字符串. revi ...

  6. 影子节点 shadowDOM

    示例: <video controls autoplay name="media"> <source id="mp4" src="t ...

  7. day 4 - 1 列表

    1.列表的增删改查 1) append insert extend li = ["ysg",[1,2,3,4,5],"peipei","梦幻" ...

  8. iTOP-4418开发板Ubuntu系统烧写方法分享

    开发平台:迅为iTOP-4418开发板    系统:Ubuntu   1. TF卡读写速度测试 烧写 Ubuntu 对于 TF 卡的要求比较高,很多老旧的卡都无法烧写 Ubuntu,下面提供一种 相对 ...

  9. 核心编程9 文件和文件的输入输出 (os模块)

    1  python内建函数open和file 文件打开方便读取:f = open('文件名','模式','缓冲模式')         #'r'读取,'w'写入(先清空后创建).'a'追加 详情文件模 ...

  10. 对mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁概念的理解

    乐观锁 乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了. 实现: 通常实现是 ...