洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]
思路
显然,为了达到这个最小公倍数,只能走\(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]最小公倍数 [分块,并查集]的更多相关文章
- 洛谷P3247 [HNOI2016]最小公倍数(分块 带撤销加权并查集)
题意 题目链接 给出一张带权无向图,每次询问\((u, v)\)之间是否存在一条路径满足\(max(a) = A, max(b) = B\) Sol 这题居然是分块..想不到想不到..做这题的心路历程 ...
- [BZOJ4537][HNOI2016]最小公倍数(分块+并查集)
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1687 Solved: 607[Submit][Stat ...
- bzoj 4537: [Hnoi2016]最小公倍数 分块+并查集
题目大意: 给定一张n个点m条边的无向图,每条边有两种权.每次询问某两个点之间是否存在一条路径上的边的两种权的最大值分别等于给定值. n,q <= 50000. m <= 100000 题 ...
- Bzoj1015/洛谷P1197 [JSOI2008]星球大战(并查集)
题面 Bzoj 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...
- 洛谷1525 关押罪犯NOIP2010 并查集
问题描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两 ...
- 洛谷P1525 关押罪犯(并查集、二分图判定)
本人蒟蒻,只能靠题解AC,看到大佬们的解题思路,%%%%%% https://www.luogu.org/problemnew/show/P1525 题目描述 S城现有两座监狱,一共关押着N名罪犯,编 ...
- 洛谷 P2661 信息传递 Label:并查集||强联通分量
题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...
- 洛谷 P1111 修复公路 Label:并查集
题目背景 A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车.政府派人修复这些公路. 题目描述 给出A地区的村庄数N,和公路数M,公路是双向的.并告诉你每条公路的连着哪两个村庄,并告诉你什么时 ...
- 洛谷P3367 【模板】并查集
P3367 [模板]并查集 293通过 551提交 题目提供者HansBug 标签 难度普及- 提交 讨论 题解 最新讨论 不知道哪错了 为啥通不过最后三个节点 题解 不懂为什么MLE 最后一个数 ...
随机推荐
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- tensorflow--logistic regression
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist=input_data. ...
- [C++]Linux之网络实时检测功能
声明:如需引用或者摘抄本博文源码或者其文章的,请在显著处注明,来源于本博文/作者,以示尊重劳动成果,助力开源精神.也欢迎大家一起探讨,交流,以共同进步,乃至成为朋友- 0.0 由于学习操作系统实验课程 ...
- 可见参数和增强for以及自动拆装箱
可变参数:定义方法的时候不知道该定义多少个参数格式: 修饰符 返回值类型 方法名(数据类型… 变量名){ } 注意: 这里的变量其实是一个数组如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定 ...
- luogu P4091 [HEOI2016/TJOI2016]求和
传送门 这一类题都要考虑推式子 首先,原式为\[f(n)=\sum_{i=0}^{n}\sum_{j=0}^{i}S(i,j)*2^j*j!\] 可以看成\[f(n)=\sum_{j=0}^{n}2^ ...
- computed,methods,watch
加载顺序: 在官方文档中,强调了computed区别于method最重要的两点 computed是属性调用,而methods是函数调用 computed带有缓存功能,而methods不是 计算属性是基 ...
- no plugin found for prefix 'tomcat 7' in the current project
使用maven build编译出错 “no plugin found for prefix 'tomcat 7' in the current project..........” 参照下面方法 ht ...
- Servlet 线程安全
普通类的静态属性,当被多个线程访问时,就有线程安全问题: Servlet 也一样 当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Se ...
- Fresco,Glide,Picasso
1.Picasso和Glide的with后面的参数不同 Picasso.with(这里只能传入上下文) . Glide.with,后面可以传入上下文,Application实例,Activit ...
- php编程 之 php基础一
1,语法 PHP 脚本在服务器上执行,然后将纯 HTML 结果发送回浏览器.PHP 文件通常包含 HTML 标签和一些 PHP 脚本代码 比如下面这个:这是一个简单的 PHP 文件实例,它可以向浏览器 ...