我们开门见山,讲讲一道sb题:

给你一个数组,查这个数组的第x大元素。

排序?可以

二分?怎么做啊?

二分出一个mid,判断这个数组中有多少个数小于等于mid,如果个数大于等于x,就递归到[l,mid]区间,否则是[mid+1,r]区间,这样递归下去就能得到结果。

怎么计算小于等于mid的个数?

for一遍原数组?其实只要存储数组中值在[l,r]中的数,然后计算就好,而对于[1,l-1],可以预先存储。

怎么计算?树状数组,范围太大就离散化。

这样很麻烦吧?排序更好吧?

但是当我给你多个询问时,你就不会这么觉得了。

回顾刚才的过程,我们做上图的类比。

把询问看成球,答案的区间就是这个矩形,每一次我们将上一层的球判断它会掉到下层的哪一块中,掉到底层就是获得了答案。

刚刚的过程就是球只有1个的情况。

球有多个时,就是整体二分!

就是对于当前的mid,对每一个询问都计算答案是大了还是小了,然后决定分配到下一层的哪边。

要注意保证时间复杂度哦!

一道例题:HDU 5412。

查询区间K小,要支持单点修改。

看代码:

 1 #include<cstdio>
 2 int n,q,a[100001],sum[300001],ans[300001],que1[300001],que2[300001],bit[300001];
 3 int I[300001],type[300001],ql[300001],qr[300001],k[300001],cnt;
 4 inline void ins(int t,int l,int r,int x){type[++cnt]=t,ql[cnt]=l,qr[cnt]=r,k[cnt]=x,I[cnt]=cnt;}
 5 inline void Ins(int i,int x){for(;i<=n;bit[i]+=x,i+=i&-i);}
 6 inline int Qur(int i){int Sum=0;for(;i;Sum+=bit[i],i-=i&-i);return Sum;}
 7 void divide(int l,int r,int low,int upp){
 8     if(l>r) return;
 9     if(low==upp) {for(int i=l;i<=r;++i) if(type[I[i]]==3) ans[I[i]]=low; return;}
10     int mid=low+upp>>1,cl=0,cr=0;
11     for(int i_=l,i;i_<=r;++i_){
12         i=I[i_];
13         if(type[i]==1) {if(k[i]<=mid) Ins(ql[i],1), que1[++cl]=i; else que2[++cr]=i;}
14         if(type[i]==2) {if(k[i]<=mid) Ins(ql[i],-1), que1[++cl]=i; else que2[++cr]=i;}
15         if(type[i]==3){
16             int tmp=Qur(qr[i])-Qur(ql[i]-1);
17             if(k[i]<=sum[i]+tmp) que1[++cl]=i;
18             else que2[++cr]=i, sum[i]+=tmp;
19         }
20     }
21     for(int i_=l,i;i_<=r;++i_){
22         i=I[i_];
23         if(type[i]==1) if(k[i]<=mid) Ins(ql[i],-1);
24         if(type[i]==2) if(k[i]<=mid) Ins(ql[i],1);
25     }
26     for(int i=1;i<=cl;++i) I[l+i-1]=que1[i];
27     for(int i=1;i<=cr;++i) I[l+cl+i-1]=que2[i];
28     divide(l,l+cl-1,low,mid); divide(l+cl,r,mid+1,upp);
29 }
30 int main(){
31     scanf("%d",&n);
32     for(int i=1;i<=n;++i) scanf("%d",a+i), ins(1,i,i,a[i]);
33     scanf("%d",&q);
34     for(int i=1,t,x,y,z;i<=q;++i){
35         scanf("%d",&t);
36         if(t==1) scanf("%d%d",&x,&y), ins(2,x,x,a[x]), ins(1,x,x,y), a[x]=y;
37         else scanf("%d%d%d",&x,&y,&z), ins(3,x,y,z);
38     }
39     divide(1,cnt,1,1000000000);
40     for(int i=1;i<=cnt;++i) if(ans[i]) printf("%d\n",ans[i]);
41     return 0;
42 }

View Code

一道例题:洛谷 P3332。

查询区间K大,要支持区间加入。

看代码:

 1 #include <cstdio>
 2
 3 typedef long long LL;
 4 const int MN = 50005;
 5
 6 int N, Q;
 7
 8 int opt[MN], L[MN], R[MN]; LL V[MN];
 9 int P[MN];
10 int s1[MN], s2[MN], t1, t2;
11
12 LL Sum[MN];
13 int Ans[MN];
14
15 LL b1[MN], b2[MN];
16 inline void Add(LL *b, int i, LL x) { for(; i <= N; i += i & -i) b[i] += x; }
17 inline LL Qur(LL *b, int i) { LL A = 0; for(; i; i -= i & -i) A += b[i]; return A; }
18 inline void Add(int l, int r, LL x) {
19     ++r;
20     Add(b1, l,  x), Add(b2, l,  (l - 1) * x);
21     Add(b1, r, -x), Add(b2, r, -(r - 1) * x);
22 }
23 inline LL Qur(int l, int r) {
24     --l;
25     return r * Qur(b1, r) - Qur(b2, r) - l * Qur(b1, l) + Qur(b2, l);
26 }
27
28 void Solve(int l, int r, int lb, int rb) {
29     if (lb == rb) {
30         for (int i = l; i <= r; ++i)
31             if (opt[P[i]] == 2)
32                 Ans[P[i]] = lb;
33         return ;
34     }
35     int mid = lb + rb >> 1;
36     t1 = t2 = 0;
37     for (int i = l; i <= r; ++i) {
38         if (opt[P[i]] == 1) {
39             if (V[P[i]] <= mid)
40                 s1[++t1] = P[i];
41             else {
42                 Add(L[P[i]], R[P[i]], 1);
43                 s2[++t2] = P[i];
44             }
45         }
46         else {
47             LL num = Sum[P[i]] + Qur(L[P[i]], R[P[i]]);
48             if (num >= V[P[i]])
49                 s2[++t2] = P[i];
50             else {
51                 Sum[P[i]] = num;
52                 s1[++t1] = P[i];
53             }
54         }
55     }
56     for (int i = l; i <= r; ++i) {
57         if (opt[P[i]] == 2) continue;
58         if (V[P[i]] > mid)
59             Add(L[P[i]], R[P[i]], -1);
60     }
61     int pos = l;
62     for (int i = 1; i <= t1; ++i)
63         P[pos++] = s1[i];
64     for (int i = 1; i <= t2; ++i)
65         P[pos++] = s2[i];
66     int M = l + t1 - 1;
67     Solve(l, M, lb, mid);
68     Solve(M + 1, r, mid + 1, rb);
69 }
70
71 int main() {
72     scanf("%d%d", &N, &Q);
73     for (int i = 1; i <= Q; ++i) {
74         scanf("%d%d%d%lld", opt + i, L + i, R + i, V + i);
75         P[i] = i;
76     }
77     Solve(1, Q, -N, N);
78     for (int i = 1; i <= Q; ++i) {
79         if (opt[i] == 1) continue;
80         printf("%d\n", Ans[i]);
81     }
82     return 0;
83 }

View Code

转载于:https://www.cnblogs.com/PinkRabbit/p/8039083.html

【算法学习】整体二分相关推荐

  1. 经典题:poj2104-区间第k小 整体二分学习

    写在前面 区间第k小 可以说是一个很经典的数据结构题了,这道题有很多种解法比如莫队离线.主席树.整体二分等等. 之前用莫队和主席树写过这道题,今天来学习一个以前不会的算法--整体二分. 因为最近遇到一 ...

  2. 数据结构与算法学习⑤(BFS和DFS 贪心算法 二分查找)

    数据结构与算法学习⑤ 数据结构与算法学习⑤ 1.BFS和DFS 1.1.深度优先搜索算法 1.2.广度优先搜索算法 面试实战 102. 二叉树的层序遍历 104. 二叉树的最大深度 515. 在每个树 ...

  3. 【学习笔记】整体二分

    文章目录 引 整体二分 几道模板题 Dynamic Rankings [ZJOI2013]K大数查询 [国家集训队]矩阵乘法 [THUPC2017] 天天爱射击 [CTSC2018]混合果汁 引 例1 ...

  4. 【cdq分治】cdq分治与整体二分学习笔记Part2.cdq分治

    上午的学习学会了整体二分,下午学了cdq分治 发现了二者的区别: 整体二分的主体是在不断地二分答案(把所有询问二分),而cdq分治则是在不断地二分操作. 当然同样的,cdq分治的复杂度也是与区间长度正 ...

  5. 【cdq分治】cdq分治与整体二分学习笔记Part1.整体二分

    之所以把cdq分治和整体二分放在一起学习,是因为他们两个实在太像了-不管是做法还是代码- 感觉整体二分可能会比cdq分治稍微简单那么一点点?所以先学整体二分. 整体二分是对答案进行二分,其具体操作如下 ...

  6. 数据结构和算法学习指南

    点击上方蓝字设为星标 下面开始今天的学习- 这篇文章会涵盖之前的所有内容,并且会举很多代码的实例,谈谈如何使用框架思维,并且给对于算法无从下手的朋友给一点具体可执行的刷题建议. 首先,这里讲的都是普通 ...

  7. [总结]CDQ分治整体二分

    从昨天到现在除了90%的颓废时间一直在研究一些分治的姿势,主要就是CDQ分治和整体二分. 首先推荐一些学习资料: 陈丹琦 <从 < Cash > 谈一类分治算法的应用> 许昊然 ...

  8. 算法学习之道,应有三重境界

    https://www.toutiao.com/a6712297555167805966/ 王国维先生在<人间词话>中写道:古今之成大事业.大学问者,必经过三种境界:"昨夜西风凋 ...

  9. C++初级算法-学习笔记

    目录 算法的基本概念 什么是算法 什么是数据结构 模拟与高精度 模拟算法 高精度运算 算法评价与算法复杂度 算法"评价员" 如何评价算法 暴力枚举 枚举 子集枚举 排列枚举 排序 ...

最新文章

  1. 宝塔Linux/Windows面板如何添加网站?附图文教程
  2. 软件研发之道——知识产权
  3. 全球农企对话国际农民丰收节贸易会·万祥军:拜耳谋定领先
  4. 性能测试监控工具nmon安装及使用方法
  5. ELK日志管理之——kibana部署
  6. 机器学习之sklearn——主题模型
  7. osg布告板技术(Billboard)
  8. C语言的typedef用法
  9. 1033. 旧键盘打字(20)-浙大PAT乙级真题
  10. 在 IE 中使用 Windows 窗体控件
  11. 影视APP直播盒子源码 第三方接口无需采集
  12. MATLAB矩阵基本运算
  13. BOS物流项目注册流程图
  14. linux虚拟磁带机管理,linux虚拟磁带机
  15. Hive beeline连接hiveserver2报错:User: root is not allowed to impersonate root
  16. Windows窗口程序
  17. 仅以此篇纪念负数取模
  18. 微信公众号的黑色商业链揭秘
  19. html中onfocus作用,HTML onfocus用法及代码示例
  20. 计算机网络_实验5_集线器与交换机对比

热门文章

  1. 修饰符.lazy .number .trim
  2. 编写高效的PyTorch代码技巧(上)
  3. python网络编程知识点_python 网络编程要点
  4. HTML——meta标签
  5. Notepad++连接VMWare中Linux只能看到/root目录
  6. Dubbo中的监控和管理
  7. Jmeter脚本增强之参数化(多方式实现)(6)
  8. BZOJ 1086 [SCOI2005]王室联邦(树分块)
  9. PAT——1027. 打印沙漏
  10. 【可持久化线段树】【主席树】[HDU4417]Super Mario