整体二分

news/2024/11/24 13:35:26/

引入

我们看一道题:

给定一个长度为 n(n≤50000)n(n\leq 50000)n(n50000) 的数组 a1,a2,...,ana_1 , a_2 , ... , a_na1,a2,...,anq(q≤10,000)q\ ( q \leq 10,000 )q (q10,000) 次询问,每次询问:

  • QQQ iii jjj kkk 表示区间 [i,j][i,j][i,j] 中第 kkk 小的数是多少,并输出这个数。
  • CCC iii ttt 表示将第 iii 个数改为 ttt

我们会发现这是一道主席树的题。

这道题很明显能用主席树来完成,但我们有其他更加简便的算法,于是我们来看看这个新的算法——整体二分。

思路

对于单个查询我们可以二分解决,但是查询往往是一系列的,这也就导致了时间过长,于是我们来想想如何解决。

我们还是用二分的思想来解决,于是我们可以将所有的操作(修改和查询)一起来二分。

每次二分都可以完成多次操作,所以就不会有同一个地方被多次查询(或修改)操作。

可以看下代码理解(上面题的,有注释):

struct node {int a, b, c, d, tp, sum;//tp记录当前是哪一种操作//若tp = 1,则是插入操作,a代表第几个数插入,b代表插入的值//若tp = 2,则是删除操作,a代表第几个数删除,b代表删除的值//若tp = 3,则是查询操作,a代表查询的左端点,b代表查询的右端点,c代表所求的k,d代表当前是第几次查询,sum代表若二分到l, r是,再a, b区间里面值域再1, l - 1的数的个数
} q[1000005], q1[1000005], q2[1000005];
void divide(int hd, int tl, int l, int r) {if (hd > tl || l == r) {//如果我们现在这个二分里面没有任何操作或者已经无法二分了for (int i = hd; i <= tl; i++)if (q[i].tp == 3)ans[q[i].d] = l;//这说明当前的答案已经找到return ;}int mid = (l + r) / 2;for (int i = hd; i <= tl; i++) {//将每个操作二分if (q[i].tp == 1 && q[i].b <= mid)add(q[i].a, 1);//我们用树状数组维护值域为l, mid的数的个数if (q[i].tp == 2 && q[i].b <= mid)add(q[i].a, -1);if (q[i].tp == 3)tmp[i] = find(q[i].b) - find(q[i].a - 1);//这里是判断再查询的区间里面有多少个值域在l, mid的数}for (int i = hd; i <= tl; i++) {//清空树状数组,注意不能全部清空,要不会TLEif (q[i].tp == 1 && q[i].b <= mid)add(q[i].a, -1);if (q[i].tp == 2 && q[i].b <= mid)add(q[i].a, 1);}int cnt1 = 0, cnt2 = 0;for (int i = hd; i <= tl; i++) {if (q[i].tp == 3) {if (q[i].sum + tmp[i] < q[i].c)//如果我们发现值域为1, mid的个数要比我们需要的少,我们就将它放入值域为mid + 1, r里面继续二分q2[++cnt2] = q[i], q2[cnt2].sum += tmp[i];else//否则就放到l, mid里面二分q1[++cnt1] = q[i];}else {if (q[i].b <= mid)//如果这个修改操作是在l, mid的区间里的,那就放在l, mid里面二分q1[++cnt1] = q[i];else//否则就放到mid + 1, r里面二分q2[++cnt2] = q[i];}}for (int i = hd; i < hd + cnt1; i++)q[i] = q1[i - hd + 1];for (int i = hd + cnt1; i < hd + cnt1 + cnt2; i++)q[i] = q2[i - hd - cnt1 + 1];//我们将操作分为两组divide(hd, hd + cnt1 - 1, l, mid);divide(hd + cnt1, tl, mid + 1, r);
}
int main() {scanf("%d%d", &n, &Q);for (int i = 1; i <= n; i++)scanf("%d", &num[i]),++cnt, q[cnt].a = i, q[cnt].b = num[i], q[cnt].tp = 1;//这里是插入操作for (int i = 1, a, b, c; i <= Q; i++) {if (in() == 'Q')scanf("%d%d%d", &a, &b, &c),++cnt, q[cnt].a = a, q[cnt].b = b, q[cnt].c = c,q[cnt].d = ++qcnt, q[cnt].tp = 3;else {scanf("%d%d", &a, &b);++cnt, q[cnt].a = a, q[cnt].b = num[a], q[cnt].tp = 2;++cnt, q[cnt].a = a, q[cnt].b = b, q[cnt].tp = 1;//我们把修改操作改成删除和插入操作num[a] = b;}}divide(1, cnt, 0, 1e9);for (int i = 1; i <= qcnt; i++)printf("%d\n", ans[i]);return 0;
}

其实二分答案的核心就是我们要尽量少作重复的二分,把每一次修改操作和查询操作都放在一起二分,以减少重复的二分次数。

例题

  • Dynamic Rankings(也就是开始那道题)

http://www.ppmy.cn/news/43543.html

相关文章

【手把手刷CCF】202303-2-垦田计划100分(超简单思路,含详细解释注释与代码)

文章目录&#xff1a;故事的开头总是极尽温柔&#xff0c;故事会一直温柔……&#x1f49c;一、&#x1f333;代码如下&#xff1a;二、&#x1f335;解题思路❤️❤️❤️忙碌的敲代码也不要忘了浪漫鸭&#xff01;故事的开头总是极尽温柔&#xff0c;故事会一直温柔……&…

【c++初阶】命名空间的定义

命名空间的定义一.缺陷二.namespace和::三.访问namespace四.一些注意1.工程里标准库的展开2.命名域的小技巧一.缺陷 在c语言中&#xff0c;如果我们同时定义一个全局变量和一个局部变量并且使用同一个名称的话&#xff0c;是可以编过的&#xff08;因为全局和局部是属于两个不同…

SSL/TLS协议实战详解

目录 1、什么是 SSL/TLS协议&#xff1f; 2、SSL协议和TLS协议的关系 3、如何使用SSL/TLS协议&#xff1f; 4、使用 HttpClient 发送一个SSL/TLS连接请求 5、浏览器端如何验证数字证书的合法性&#xff1f; 6、如何在Nginx服务器上配置SSL/TLS协议&#xff1f; 7、如何在…

简单明了的说明STM32的PWM原理以及实现方法

申明以下都是个人理解&#xff0c;仅供参考。如果错误欢迎指教。本文不讲底层&#xff0c;根据实际使用来逆向讲解。 1.什么是pwm&#xff1f; pwm最简单的理解就是“功率”&#xff0c;调节PWM的占空比就是调节功率。 2.如何调节占空比&#xff1f; 图1 根据图1很容易看出…

代码随想录打卡第58天|739. 每日温度;496.下一个更大元素 I

739. 每日温度 关键点1&#xff1a;先前的一些准备 单调栈&#xff1a;单调栈的含义->用栈记录已经遍历过的元素&#xff0c;再将0元素压入栈 结果集&#xff1a;与给定数组一样大小&#xff0c;结果集初始化为0 关键点2&#xff1a;核心部分 for循环遍历给定数组&#…

初阶数据结构之时间复杂度和空间复杂度(一)

文章目录[TOC](文章目录)前言1.什么是数据结构&#xff1f;2.什么是算法&#xff1f;3.数据结构和算法的重要性一、算法效率1.1如何衡量一个算法的好坏2.2算法的复杂度二.时间复杂度2.1时间复杂度的概念2.2举例说明2.3大O的渐进表示法三.空间复杂度3.1空间复杂度的概念3.2举例说…

https访问fastdfs图片

引用&#xff1a;https://blog.csdn.net/love8753/article/details/128872320 配置nginx 的SSL模块&#xff1a;https://www.cnblogs.com/ghjbk/p/6744131.html 获取ssl证书 将ssl证书&#xff0c;拷贝到服务器的一个目录下 nginx添加 http_ssl_module 最开始安装的nginx只有 …

Redis常见命令

Redis是典型的key-value数据库&#xff0c;key一般是字符串&#xff0c;而value包含很多不同的数据类型&#xff1a;1. Redis通用命令 通用指令是部分数据类型的&#xff0c;都可以使用的指令&#xff0c;常见的有&#xff1a; - KEYS&#xff1a;查看符合模板的所有key- KEYS…