bzoj 4537: [Hnoi2016]最小公倍数 分块+并查集
题目大意:
给定一张n个点m条边的无向图,每条边有两种权.每次询问某两个点之间是否存在一条路径上的边的两种权的最大值分别等于给定值.
n,q <= 50000. m <= 100000
题解:
通过分析可以得到,我们能经过的所有的边的两种权一定均分别不大于给定的值.
把这些边称作可行边。那么我们把所有的可行边加入到图当中,然后判断询问的两个点是不是联通.
如果联通我们再进一步判断一下所有与其所在的联通块联通的所有边的两种边权的分别的最大值.
然后就是考虑如何快速统计出所有的边并将其加入到联通块中.
我们选择如下策略: 把所有的边按第一种权排序,然后分块.
每块内按照第二种权排序
事实证明上面划掉的方法直接TLE
我们考虑离线所有的操作,然后每次对第一种权在某一个块内的所有询问.
我们知道如果某个询问的第一种权在块i中,那么1 ~ i-`中的所有边的第一种权都符合条件.
所以这时候对1 ~ i-1块中的所有边按照第二种权排序.
如果我们处理询问的时候按照第二种权递增访问就可以做到线性统计了.
所以我们将所有此时应该处理的询问按照第二种权排序.
那么我们可以线性统计所有在1 ~ i-1块中的边完成所有此时的询问.
那么在第i个块中的呢 ?
直接暴力查询,然后维护可持久化并查集即可.
我们直接记录所有的操作,然后暴力撤销即可.
不要问我复杂度是多少,O(跑的过)
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define rg register int
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
const int maxm = 100010;
struct Edge{
int id;
int u,v,a,b;
}e[maxm],q[maxm],tmp[maxm];
int cnt;
inline bool cmpa(const Edge &a,const Edge &b){
return a.a == b.a ? a.b < b.b : a.a < b.a;
}
inline bool cmpb(const Edge &a,const Edge &b){
return a.b == b.b ? a.a < b.a : a.b < b.b;
}
int n,m;
struct Node{
int idx,idy,fa,siz,mxa,mxb;
Node(){}
Node(const int &a,const int &b,const int &c
,const int &d,const int &e,const int &f){
idx = a;idy = b;fa = c;siz = d;mxa = e;mxb = f;
}
}sta[maxm];
int top;
int fa[maxn],siz[maxn],mxa[maxn],mxb[maxn];
inline void clear(){
for(int i=1;i<=n;++i){
fa[i] = i;siz[i] = 1;
mxa[i] = mxb[i] = -1;
}
}
inline int find(int x){
while(x != fa[x]) x = fa[x];
return x;
}
inline void Union(const Edge &e){
int x = find(e.u),y = find(e.v);
if(siz[x] > siz[y]) swap(x,y);
sta[++top] = Node(x,y,fa[x],siz[y],mxa[y],mxb[y]);
mxa[y] = max(mxa[y],max(mxa[x],e.a));
mxb[y] = max(mxb[y],max(mxb[x],e.b));
if(x == y) return ;
siz[y] += siz[x];fa[x] = y;
}
inline void Undo(){
while(top){
fa[sta[top].idx] = sta[top].fa;
siz[sta[top].idy] = sta[top].siz;
mxa[sta[top].idy] = sta[top].mxa;
mxb[sta[top].idy] = sta[top].mxb;
-- top;
}
}
bool ans[maxm];
int main(){
read(n);read(m);
for(int i=1;i<=m;++i){
read(e[i].u);read(e[i].v);
read(e[i].a);read(e[i].b);
}
int Q;read(Q);
for(int i=1;i<=Q;++i){
read(q[i].u);read(q[i].v);
read(q[i].a);read(q[i].b);
q[i].id = i;
}
sort(e+1,e+m+1,cmpa);sort(q+1,q+Q+1,cmpb);
int block = sqrt(m);
for(int i=1;i<=m;i+=block){
cnt = 0;
for(int j=1;j<=Q;++j){
if(q[j].a >= e[i].a && (i+block > m || e[i+block].a > q[j].a)){
tmp[++cnt] = q[j];
}
}
sort(e+1,e+i,cmpb);clear();
for(int j=1,k=1;j<=cnt;++j){
while(k < i && e[k].b <= tmp[j].b) Union(e[k++]);
top = 0;
for(int l=i;l<i+block && l <= m;++l){
if(e[l].a <= tmp[j].a && e[l].b <= tmp[j].b) Union(e[l]);
}
int x = find(tmp[j].u),y = find(tmp[j].v);
if(x == y && mxa[x] == tmp[j].a && mxb[x] == tmp[j].b) ans[tmp[j].id] = true;
Undo();
}
}
for(int i=1;i<=Q;++i) puts(ans[i] ? "Yes" : "No");
return 0;
}
其实复杂度是:\(O( m\sqrt{m}logm + q(logn+logq))\)的
bzoj 4537: [Hnoi2016]最小公倍数 分块+并查集的更多相关文章
- [BZOJ4537][HNOI2016]最小公倍数(分块+并查集)
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1687 Solved: 607[Submit][Stat ...
- BZOJ 4537: [Hnoi2016]最小公倍数 [偏序关系 分块]
4537: [Hnoi2016]最小公倍数 题意:一张边权无向图,多组询问u和v之间有没有一条a最大为a',b最大为b'的路径(不一定是简单路径) 首先想到暴力做法,题目要求就是判断u和v连通,并查集 ...
- bzoj 4537 HNOI2016 最小公倍数
Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,-,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在有q个询问,每次询问给定四个参数u.v.a和b,请你 ...
- 洛谷P3247 最小公倍数 [HNOI2016] 分块+并查集
正解:分块+并查集 解题报告: 传送门! 真的好神仙昂QAQ,,,完全想不出来,,,还是太菜了QAQ 首先还是要说下,这题可以用K-D Tree乱搞过去(数据结构是个好东西昂,,,要多学学QAQ),但 ...
- BZOJ.2054.疯狂的馒头(并查集)
BZOJ 倒序处理,就是并查集傻题了.. 并查集就是确定下一个未染色位置的,直接跳到那个位置染.然而我越想越麻烦=-= 以为有线性的做法,发现还是要并查集.. 数据随机线段树也能过去. //18400 ...
- [APIO2019] [LOJ 3145] 桥梁(分块+并查集)(有详细注释)
[APIO2019] [LOJ 3145] 桥梁(分块+并查集)(有详细注释) 题面 略 分析 考试的时候就感觉子任务4是突破口,结果却写了个Kruskal重构树,然后一直想怎么在线用数据结构维护 实 ...
- P5443 [APIO2019]桥梁 [分块+并查集]
分块+并查集,大板子,没了. 并查集不路径压缩,可撤销,然后暴力删除 这样对于每个块都是独立的,所以直接搞就行了. 然后块内修改操作搞掉,就是单独的了 // powered by c++11 // b ...
- 2021.08.03 BZOJ 疯狂的馒头(并查集)
2021.08.03 BZOJ 疯狂的馒头(并查集) 疯狂的馒头 - 题目 - 黑暗爆炸OJ (darkbzoj.tk) 重点: 1.并查集的神奇运用 2.离线化 题意: 给一个长为n的序列,进行m次 ...
- 洛谷P3247 [HNOI2016]最小公倍数(分块 带撤销加权并查集)
题意 题目链接 给出一张带权无向图,每次询问\((u, v)\)之间是否存在一条路径满足\(max(a) = A, max(b) = B\) Sol 这题居然是分块..想不到想不到..做这题的心路历程 ...
随机推荐
- IOS中UITableView异步加载图片的实现
本文转载至 http://blog.csdn.net/enuola/article/details/8639404 最近做一个项目,需要用到UITableView异步加载图片的例子,看到网上有一个E ...
- 【BZOJ5020】[THUWC 2017]在美妙的数学王国中畅游 泰勒展开+LCT
[BZOJ5020][THUWC 2017]在美妙的数学王国中畅游 Description 数字和数学规律主宰着这个世界. 机器的运转, 生命的消长, 宇宙的进程, 这些神秘而又美妙的过程无不可以用数 ...
- ubuntu14.04 desktop 32-bit kvm装windows xp
经过这几天来的折腾,总算是在ubuntu14.04用kvm装上了xp, 看不少的的贴,也绕了不少的圈,总的来说,非常感谢CSDN上的"上善若水75",看着他写的一个分类" ...
- Web框架的引入
为什么会有web框架 有了上一篇内容,静态.动态web服务器的实现,已经掌握了客户端请求到服务器处理的机制.在动态资源处理中,根据请求 .py 导入模块应用,然后调用应用入口程序实现动态处理.但是在真 ...
- 九度OJ 1204:农夫、羊、菜和狼的故事 (遍历、BFS)
时间限制:1 秒 内存限制:32 兆 特殊判题:是 提交:744 解决:502 题目描述: 有一个农夫带一只羊.一筐菜和一只狼过河. 果没有农夫看管,则狼要吃羊,羊要吃菜. 但是船很小,只够农夫带一样 ...
- csv文件的格式
csv, comma separated values csv是一种纯文本文件. csv文件由任意数目的记录构成,记录间以换行符分割,每条记录由字段构成,字段间以逗号作为分隔符. 如果字段中有逗号,那 ...
- HTML-Table-Td固定宽度使内容换行
table style="TABLE-LAYOUT: fixed;" td style="WORD-WRAP: break-word;WIDTH:200px;"
- Android笔记之获取debug.keystore和release.keystore的MD5/SHA1值
获取debug.keystore的key,如下图 获取release.keystore的key 输入命令keytool -list -v -keystore <jksFilename> 例 ...
- PAT 1063. 计算谱半径(20)
在数学中,矩阵的“谱半径”是指其特征值的模集合的上确界.换言之,对于给定的n个复数空间的特征值{a1+b1i, ..., an+bni},它们的模为实部与虚部的平方和的开方,而“谱半径”就是最大模. ...
- javascript操作常见的html标签
几乎HTML所有标记都可以说是HTML的控件,如select, input, div, table等.html标签便捷的操作,深受大家的喜欢.现在的大部分网站都是ajax+json来进行数据传送.所以 ...