整体二分是一个离线的做法  目前可以解决求区间第k大问题

当然划分树主席树都可以的样子.. 为什么我老学一些解决同种问题的算法..

主要思想大概是这样的:

如果要求[l,r]的区间第K大 而这个区间内如果有多于K个数字 那么多出来的数字其实是不会影响到什么的

所以我们整体二分一下答案 即 把二分值对于每一个操作 都尝试一发 于是会发现 如果当前我们二分答案是x 那么大于x的数字是没有意义的 算出来小于x的数字有多少 然后做一个类似于划分树思想的操作 分出lq rq两个队列 把<=x的相关操作强制堆到lq里面 >x的堆到rq里面 被扔到rq里面的query询问会出现 q[i].k -= (小于当前二分值x的个数)

于是 每一次二分 都会分出lq rq 而rq里面的操作 是不会影响到lq的 因为rq操作的数字 要么在询问之后 要么已经>k了

当l==r的时候 对当前消息队列筛选出所有query 记录答案 = l

每次处理出lq rq之后 让q = lq 和 rq 然后去处理这两个部分 因为把<=x的强制扔到lq里面了 也就保证了lq里面如果有询问 ans一定在l mid 这个区间里面

这样一直down下去 不需要up

在这个求区间k大的做法里面 记录区间内数字的做法是:

由于我们已经确定这个伪ans(二分值)了 我们就只算<=x的 数字的个数

我们假想这个a数列一开始是空的 每一个赋值都是对一个位置插入一个数字

并且我们保证了处理的当前操作队列[ql , qr] 里面的数字操作都是 [l , r]里面的 于是 小于伪ans的增删操作 对其做一下树状数组的add

如何查询当前的询问 应该被归类到哪个队列:

看[q[i].l , q[i].r] 这个区间内 有 多少个值 由于增删的时候只对<=x做操作 所以求出来的sum是这个区间内<=x的值 就可以决定把这个操作扔到哪个队列

由于每次都是对当前[ql,qr]操作队列进行 所以开始面对的总是一个空的树状数组c[] 所以最后需要对add(x,val)的操作进行一个add(x,-val)的操作 可以省去memset的时间

如果要做更改的操作 就可以拆分成增加与减少两个操作

支持在二维的区间上查询第k大 需要使用二维树状数组

在拆分成两个队列后 两个队列里的操作互相不影响 但是 每个队列里面 操作的相对前后是不变的 两个队列的相对前后可能因为分到不同队列发生改变 改变的都是无关的

二维区间查询第k大 Tsinsen A1333

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<string>
#include<iostream>
#include<vector>
using namespace std;
#define L long long
#define pb push_back
const int N = 505 * 505 + 60050 ;
struct node {
int x1 , y1 , x2 , y2 , z , id , tp ;
}q[N] , lq[N] , rq[N] ;
int n , m ;
int c[505][505] ;
int ans[60050] ;
int lowbit(int x) {return (x&(-x)) ; }
void add(int x,int y,int val) {
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=n;j+=lowbit(j)) {
c[i][j]+=val;
}
}
}
int sum(int x,int y) {
int val = 0 ;
for(int i=x;i>0;i-=lowbit(i)){
for(int j=y;j>0;j-=lowbit(j)){
val+=c[i][j];
}
}
return val;
}
int sum(int x1,int y1,int x2,int y2) {
return sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1);
}
void solve(int ql , int qr , int l , int r) {
if(ql > qr || l > r) return ;
if(l == r) {
for(int i = ql ; i <= qr ; i ++ ) {
if(q[i].tp == 2) {
ans[q[i].id] = l ;
}
}
return ;
}
int lcnt = 0 , rcnt = 0 ;
int mid = (l + r) / 2 ;
for(int i = ql ; i <= qr ; i ++ ){
if(q[i].tp == 1) {
if(q[i].z <= mid) {
lq[++lcnt] = q[i] ;
add(q[i].x1,q[i].y1,q[i].id) ;
}
else {
rq[++rcnt] = q[i] ;
}
}
else {
int small = sum(q[i].x1,q[i].y1,q[i].x2,q[i].y2) ;
if(q[i].z <= small) {
lq[++lcnt] = q[i] ;
}
else {
q[i].z -= small ;
rq[++rcnt] = q[i] ;
}
}
}
for(int i = 1 ; i <= lcnt ; i ++) {
if(lq[i].tp == 1) {
add(lq[i].x1,lq[i].y1,-lq[i].id) ;
}
}
for(int i = 1 ; i <= lcnt ; i ++ ) q[i + ql - 1] = lq[i] ;
for(int i = 1 ; i <= rcnt ; i ++ ) q[i + ql + lcnt - 1] = rq[i] ;
solve(ql,ql+lcnt-1,l,mid);
solve(ql+lcnt,qr,mid+1,r);
}
int main(){
scanf("%d%d",&n,&m);
memset(c,0,sizeof(c));
int cnt = 0 ;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x;
scanf("%d",&x);
cnt ++ ;
q[cnt].x1=i,q[cnt].y1=j,q[cnt].z=x,q[cnt].tp=1,q[cnt].id=1;
}
for(int i=1;i<=m;i++){
int x1,y1,x2,y2,k;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
cnt ++ ;
q[cnt].x1=x1,q[cnt].x2=x2,q[cnt].y1=y1,q[cnt].y2=y2,q[cnt].z=k,q[cnt].id=i,q[cnt].tp=2;
}
solve(1,cnt,0,1000000000);
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}

-------------

又进行了一些学习 发现不止可以解决求k大

可以解决一些满足“二分性”和“无后效性”的问题

是一个把所有询问(和操作)一起读入 最后一起二分的做法

比如poi2011meteors 就是一个整体二分的例子

其实操作队列中只有询问某个国家        l r 代表当前答案的可能范围 先做出[l,mid]的流星雨的结果 然后check操作队列中的每一个国家 足够的lq以寻求最小

不足够的扔到rq 并且减去[l,mid]得到的流星 于是 关注点就只在它能在[mid+1,r]中得到多少流星了

(五角星) 因为过去的流星 这个国家已经收集到了 当我们考虑这个国家的ans在[mid+1,r]的哪里时 过去的事情无需考虑 直接减去那段时光造成的所有影响就可以了

整体二分learning的更多相关文章

  1. 整体二分QAQ

    POJ 2104 K-th Number 时空隧道 题意: 给出一个序列,每次查询区间第k小 分析: 整体二分入门题? 代码: #include<algorithm> #include&l ...

  2. BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

    [题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...

  3. [bzoj1901][zoj2112][Dynamic Rankings] (整体二分+树状数组 or 动态开点线段树 or 主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  4. bzoj 2527: [Poi2011]Meteors 整体二分

    给每个国家建一个链表,这样分治过程中的复杂度就和序列长度线形相关了,无脑套整体二分就可以. (最坑的地方是如果所有位置都是一个国家,那么它的样本个数会爆longlong!!被这个坑了一次,大于p[i] ...

  5. 【BZOJ-2527】Meteors 整体二分 + 树状数组

    2527: [Poi2011]Meteors Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 831  Solved: 306[Submit][Stat ...

  6. BZOJ 1901 Zju2112 Dynamic Rankings ——整体二分

    [题目分析] 上次用树状数组套主席树做的,这次用整体二分去水. 把所有的查询的结果一起进行二分,思路很好. [代码] #include <cstdio> #include <cstr ...

  7. BZOJ 1901 & 整体二分

    题意: 带修改的区间第K小. SOL: 看了很久很久很久很久的整体二分,网上的各种题解也不是很多,也一直很不了解所谓的"贡献","将询问一起递归"是什么意思.. ...

  8. bzoj1146整体二分+树链剖分+树状数组

    其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include<cstdio> #include<cstr ...

  9. 【BZOJ 3110】 [Zjoi2013]K大数查询(整体二分)

    [题目] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到 ...

随机推荐

  1. 三、docker官网注册docker id

    docker官网注册docker ID 电脑注册docker没有成功,网上有人说用手机注册,试了一下确实可以注册. 1.下载蓝灯软件开启FQ代理. 2.登录网站,按照提示注册.

  2. git push 推送大文件失败的处理办法

    不小心把数据库备份文件放到git目录里了,导致无法上传代码. 首先参考了 这篇文章 http://www.cnblogs.com/qmmq/p/4604862.html. 按照文中一开始说的去做,可还 ...

  3. Toeplitz matrix

    w https://en.wikipedia.org/wiki/Toeplitz_matrix Proof of Stolz-Cesaro theorem | planetmath.org  http ...

  4. What are DESC and ASC Keywords?

    What are DESC and ASC Keywords? ASC is the short form for ascending DESC is the short form for desce ...

  5. access 如何导出 cvs 文件?

    三部曲 1 access 数据表导出 excel 表格 2 excel 另存为 *.cvs 格式文件 3 数据库导入 *.cvs 文件

  6. 洛谷 P3263 [JLOI2015]有意义的字符串

    洛谷 首先,看到\((\frac{(b+\sqrt{d})}{2})^n\),很快能够想到一元二次方程的解\(\frac{-b\pm\sqrt{\Delta}}{2a}\). 所以可以推出,\(\fr ...

  7. Mysql在大型网站的应用架构演变(转)

    原文: Mysql在大型网站的应用架构演变 本文已经被多处转载,包括CSDN推荐以及码农周刊等等,阅读数超过5w+,回流到我博客流量的还是比较少,不过这不重要, 后续会分享更多技术,尽量试图把自己理解 ...

  8. (4.11)sql server内存使用

    一些内存使用错误理解   开篇小感悟 在实际的场景中会遇到各种奇怪的问题,为什么会感觉到奇怪,因为没有理论支撑的东西才感觉到奇怪,SQL Server自己管理内存,我们可以干预的方式也很少,所以日常很 ...

  9. python ipython notebook或者 jupyter notebook 的安装

    IPython Notebook使用浏览器作为界面,向后台的IPython服务器发送请求,并显示结果.在浏览器的界面中使用单元(Cell)保存各种信息.Cell有多种类型,经常使用的有表示格式化文本的 ...

  10. openresty安装文档

    一.OpenResty简介    OpenResty是一个基于 Nginx与 Lua的高性能 Web平台,其内部集成了大量精良的 Lua 库.第三方模块以及大多数的依赖项.用于方便地搭建能够处理超高并 ...