链接

loj

一道阔爱的分块

题意

边权是二元组(A, B),每次询问u, v, a, b,求u到v是否存在一条简单路径,使得各边权上\(A_{max} = a, B_{max} = b\)

分析

对于这种有两种限制的题目

一般的套路就是条件按照第一种权值为关键字排序,询问按照第二种关键字排序

然后给条件分块,然后对于一个块只把第一关键字符合条件的询问放进去

在把当前块前面的整块里的点按照第二关键字排序

这样当前块前面的点都是符合当前询问点对于第一关建字条件的

而且第二关键字都是单调的,所以扫一下

然后对于每个询问,暴力处理一下当前块的贡献

[参考BeNoble_] (https://blog.csdn.net/benoble_/article/details/79777757)

对于这道题 如果暴力怎么做?

对于询问u, v, a, b

把所有满足A<= a, B <= b的边加进来

因为只要最大值,所以可以维护一个带权并查集(find的时候不更新father哦)

(小声:其实这个带权并查集就像一个树一样

然后查询一下是否连通,连通的话所在并查集最大权满不满足条件(即Amax == a && Bmax == b)

所以说,分块的本质都是暴力

然后复杂度就在这个加边上了

就像最前面说的那样加 加完把不整块的删了 okk

框架就像这样

询问按b排序 边按a排序

for(对于每一个块){
收集a大小在该块范围内的询问 按b排前面整块的点(这样后面就单调了 初始化并查集 for(对于每一个询问){
加前面整块里 b满足条件的边(a必然满足条件) 加不整块的a,b都满足条件的边 判定是否联通且满足条件 还原不整块的边
}
}

最后附上代码

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
using namespace std;
const int N = 1e5 + 5; int n, m, qsize;
struct E{
int u, v, a, b, id;
}e[N], q[N];
struct Opt{
int u, v, a, b, fa, size;
}opt[N];
bool ans[N];
int blsize;
int b[N], bcnt, tim;
int fa[N], mxa[N], mxb[N], size[N]; bool rulea(E x, E y){return x.a < y.a;}
bool ruleb(E x, E y){return x.b < y.b;} int find(int x){
return x == fa[x] ? x : find(fa[x]);
} inline void merge(E x, bool type){
x.u = find(x.u); x.v = find(x.v);
if(size[x.u] > size[x.v]) swap(x.u, x.v);
//printf("do %d %d %d\n", x.u, x.v, type);
if(type) {
++tim;
opt[tim].u = x.u, opt[tim].v = x.v; opt[tim].fa = fa[x.u];
opt[tim].a = mxa[x.v], opt[tim].b = mxb[x.v];
opt[tim].size = size[x.v];
} if(find(x.u) == find(x.v)){
mxa[x.v] = max(mxa[x.v], x.a);
mxb[x.v] = max(mxb[x.v], x.b);
}
else {// u -> v
fa[x.u] = x.v;
size[x.v] += size[x.u];
mxa[x.v] = max(mxa[x.v], x.a);
mxb[x.v] = max(mxb[x.v], x.b);
mxa[x.v] = max(mxa[x.v], mxa[x.u]);
mxb[x.v] = max(mxb[x.v], mxb[x.u]);
}
} inline void undo(){
while(tim){
// printf("undo %d %d\n", opt[tim].u, opt[tim].v);
fa[opt[tim].u] = opt[tim].fa;
mxa[opt[tim].v] = opt[tim].a;
mxb[opt[tim].v] = opt[tim].b;
size[opt[tim].v] = opt[tim].size;
--tim;
}
} int main(){
scanf("%d%d", &n, &m);
blsize = sqrt(15 * m);//
for(int i = 1; i <= m; ++i){
scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);
}
sort(e + 1, e + m + 1, rulea);
scanf("%d", &qsize);
for(int i = 1; i <= qsize; ++i){
scanf("%d%d%d%d", &q[i].u, &q[i].v, &q[i].a, &q[i].b);
q[i].id = i;
}
sort(q + 1, q + qsize + 1, ruleb); // for(int i = 1; i <= m; ++i)
// printf("%d %d %d %d\n", e[i].u, e[i].v, e[i].a, e[i].b); for(int i = 1, lim; i <= m; i += blsize){
bcnt = 0;
lim = min(m, i + blsize - 1);
for(int j = 1; j <= qsize; ++j)
if(e[i].a <= q[j].a
&& (i + blsize > m || e[i + blsize].a > q[j].a))
b[++bcnt] = j;
sort(e + 1, e + i, ruleb);//这里排的是前面整块的点!
for(int j = 1; j <= n; ++j){
fa[j] = j, size[j] = 1, mxa[j] = mxb[j] = -1;
}
for(int j = 1, top = 1; j <= bcnt; ++j){
while(top < i && q[b[j]].b >= e[top].b){
//printf("mer %d 0\n");
merge(e[top], 0);
++top;
}
for(int k = i; k <= lim; ++k){
if(q[b[j]].a >= e[k].a && q[b[j]].b >= e[k].b){
merge(e[k], 1);
}
} int x = find(q[b[j]].u), y = find(q[b[j]].v);
//printf("%d %d %d %d %d %d %d\n", q[b[j]].u, q[b[j]].v, q[b[j]].id, mxa[x], mxb[x], x, y);
ans[q[b[j]].id] = ((x == y) && (mxa[x] == q[b[j]].a) && (mxb[x] == q[b[j]].b)); undo();
}
}
for(int i = 1; i <= qsize; ++i)
if(ans[i]) printf("Yes\n");
else printf("No\n");
return 0;
}

「HNOI2016」最小公倍数的更多相关文章

  1. 「HNOI2016」最小公倍数 解题报告

    「HNOI2016」最小公倍数 考虑暴力,对每个询问,处理出\(\le a,\le b\)的与询问点在一起的联通块,然后判断是否是一个联通块,且联通块\(a,b\)最大值是否满足要求. 然后很显然需要 ...

  2. loj2048 「HNOI2016」最小公倍数

    link 题意: 给定一张$N$个顶点$M$条边的无向图(顶点编号为$1,2,...,n$),每条边上带有权值.所有权值都可以分解成$2^a \cdot 3^b$的形式. 现在有$q$个询问,每次询问 ...

  3. LOJ #2048. 「HNOI2016」最小公倍数

    题意 有 \(n\) 个点,\(m\) 条边,每条边连接 \(u \Leftrightarrow v\) 且权值为 \((a, b)\) . 共有 \(q\) 次询问,每次询问给出 \(u, v, q ...

  4. 「HNOI2016」数据结构大毒瘤

    真是 \(6\) 道数据结构毒瘤... 开始口胡各种做法... 「HNOI2016」网络 整体二分+树状数组. 开始想了一个大常数 \(O(n\log^2 n)\) 做法,然后就被卡掉了... 发现直 ...

  5. 「HNOI2016」树 解题报告

    「HNOI2016」树 事毒瘤题... 我一开始以为每次把大树的子树再接给大树,然后死活不知道咋做,心想怕不是个神仙题哦 然后看题解后才发现是把模板树的子树给大树,虽然思维上难度没啥了,但是还是很难写 ...

  6. 「HNOI2016」序列 解题报告

    「HNOI2016」序列 有一些高妙的做法,懒得看 考虑莫队,考虑莫队咋移动区间 然后你在区间内部找一个最小值的位置,假设现在从右边加 最小值左边区间显然可以\(O(1)\),最小值右边的区间是断掉的 ...

  7. 「HNOI2016」网络 解题报告

    「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...

  8. loj #2051. 「HNOI2016」序列

    #2051. 「HNOI2016」序列 题目描述 给定长度为 n nn 的序列:a1,a2,⋯,an a_1, a_2, \cdots , a_na​1​​,a​2​​,⋯,a​n​​,记为 a[1: ...

  9. 【LOJ】#2052. 「HNOI2016」矿区

    题解 之前尝试HNOI2016的时候弃坑的一道,然后给补回来 (为啥我一些计算几何就写得好长,不过我写啥都长orz) 我们尝试给这个平面图分域,好把这个平面图转成对偶图 怎么分呢,我今天也是第一次会 ...

随机推荐

  1. 使用webview几种常见的hybrid通信方式

    js 与原生之间的通信: 1.JSbridge::(webviewJavascriptBridge)一种js与原生native通信的机制,可以h5与native互调: 2.Cordova: 核心就是原 ...

  2. kubectl常用命令汇总

    #查看k8s的所有node节点 kubectl get node #查看ns的pod kubectl get pod --all-namespaces -o wide kubectl get pod ...

  3. 第四章 MyBatis-SQL映射文件

    MyBatis 真正的强大在于映射语句,专注于SQL,功能强大,SQL映射的配置却是相当简单 SQL映射文件的几个顶级元素(按照定义的顺序) mapper - namespace cache - 配置 ...

  4. Linux系统中常用的命令汇总

    日常开发,上线的服务器系统一般都是Linux系统,所以,熟练的掌握常用的命令操作就尤其的重要了 1) 查看某个服务的运行情况 (例如Redis) ps -ef | grep redis //e-显示程 ...

  5. http1.0 1.1 与2.0

    长连接 HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接. HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一 ...

  6. 在C 与 C++混编中, 出现error LNK2019: 无法解析的外部符号 "int __cdecl main_(int,char * *)" (?main_@@YAHHPEAPEAD@Z),该符号在函数 main 中被引用

    main_ 这个函数的头文件 应该做标准化输出 : extern "C" int main_(int argc, char **argv);

  7. RedHat Enterprise Linux 6.4使用yum安装出现This system is not registered to Red Hat Subscription Management

    我虚拟机安装的系统是RedHat Enterprise Linux 6.4-i686,是32位的.使用yum命令安装软件时候出现以下错误: This system is not registered ...

  8. vue 中的slot属性(插槽)的使用

    总结如下: VUE中关于插槽的文档说明很短,语言又写的很凝练,再加上其和方法,数据,计算机等常用选项在使用频率,使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经 ...

  9. python爬虫之git的安装

      一.初始 1.发展历史 *最开始没有对代码的管理,导致很多东西混乱和丢失. *后来大家想了一个办法,用最简单最笨的方法,各种复制文件夹. *然后就出现了版本控制的工具. 1.单机版:RCS(198 ...

  10. Python深入类和对象

    一. 鸭子类型和多态 1.什么是鸭子类型: 在程序设计中,鸭子类型(英语:Duck typing)是动态类型和某些静态语言的一种对象推断风格."鸭子类型"像多态一样工作,但是没有继 ...