整体二分笔记

整体二分

本来感觉挺神秘的一个东西, 学完了似乎没有多难, 放几个板子随便写写吧(今天数学不想做题)

从最最最最人尽皆知的区间第 \(k\) 大问题开始吧

引入

如果我想问你一个序列中的区间的第 \(k\) 大,你会如何?

显然我们直接二分就行(主席树学傻的滚)

时间复杂度为 \(O(nlogn)\) 感觉挺不错的呢

但是如果我们有一大堆询问,我们的时间复杂度就会直接被干到 \(O(qnlogn)\) ,这个东西都没我快, 我们肯定是很不满意的

这时候就要引出我们的整体二分了

与其说是二分,其实我觉得更像是分治,利用可二分问题的性质

比如说我们想要解决这个经典区间第 \(k\) 大的问题

我们使用一个容器存储当前 \([l,r]\) 的加点, 询问信息

注意这里的 \([l,r]\) 和如果只有一个操作一样,指的是值而非位置,平常二分是什么这个 \(l,r\) 就是什么

我这里就使用一个存结构体的 \(vector\)

结构体里边有 \(x,y,k,id,type\)

其中 \(type\) 代表的是所记录的操作是属于添加还是删除,根据我的习惯,我们就使用 \(0\) 代表这个操作是添加, \(1\) 代表这个操作是询问

\(type=1\) 中, \(x,y,k,id\) 分别代表的是询问左端点,右端点,求第 \(k\) 大,询问编号(输出用,我们搞得离线)

\(type=0\) 中, \(x,id\) 分别代表当前位置的值和当前位置编号,其他位置没有意义

这两个的存贮是不干扰的, 为什么最好放到一个里我们之后再说,我们把所有添加放到最前面

之后我们开始我们的算法:

当前我们处理到区间 \([l,r]\) 了, 有一个容器 \(tmp\) 记录着作用于当前区间的操作

如果 \(l=r\), 即为当前已经锁定了一个值,我们就将容器中所有的询问直接设为 \(l\) 就行,注意按照 \(id\) 存储,直接返回即可,反之向下继续走

我们找出来 \(mid\),开两个容器表示我们向下 \([l,mid]\)\([mid+1,r]\) 的容器,方便我们向下分治使用,还需要一个数据结构维护我们需要的信息

在这个问题中,我们决定一个询问是向 \([l,mid]\) 还是 \([mid+1,r]\) 是取决于比当前询问 \(k\) 大的数字有几个的,我们使用树状数组就可以维护,我们首先处理添加操作

我们将值在当前 \(mid\) 左边的添加操作加上去,对应的,也就是在树状数组对应位置处加上 \(1\) (是 id 哦)

过程中我们将值小于等于 \(mid\) 的放到 \([l,mid]\) 的容器中, 反之同理

之后我们 \(mid\) 往左的都处理好了,之后对于排在后边的若干个询问,我们只需要查询在 \([x,y]\) 之间有多少个

如果比当前 \(k\) 大,这个询问放到 \([l,mid]\) ,反之同理

最后别忘了我们这个树状数组只为了我们确定询问下放的位置,对不同 \(mid\) 也不同, 我们需要清空树状数组

递归下去就行

我们放一下代码罢

代码如下↓

cpp
#include <bits/stdc++.h>
using namespace std;
const int MN=1e6;
struct Node{int x, y, k, id, type;};
struct BIT{int tr[MN], n;void init(int num){n=num; memset(tr,0,sizeof(tr));}int lowbit(int x){return x&(-x);}void update(int pos, int val){for(int i=pos; i<=n; i+=lowbit(i)) tr[i]+=val;}int qval(int pos){int res=0; for(int i=pos; i; i-=lowbit(i)) res+=tr[i];return res;}int query(int l, int r){return qval(r)-qval(l-1);}
}bit;
int n, q, ans[MN];
void solve(vector <Node> tmp, int l, int r){if(tmp.empty()) return;if(l==r){for(int j=0; j<tmp.size(); ++j)if(tmp[j].type)ans[tmp[j].id]=l;return;}int mid=(l+r)>>1;vector <Node> tmp1, tmp2;for(int j=0; j<tmp.size(); ++j){if(!tmp[j].type){if(tmp[j].x<=mid){bit.update(tmp[j].id,1);tmp1.push_back(tmp[j]);}else{tmp2.push_back(tmp[j]);}}else{int res=bit.query(tmp[j].x,tmp[j].y);if(res>=tmp[j].k){tmp1.push_back(tmp[j]);}else{tmp[j].k-=res;tmp2.push_back(tmp[j]);}}}for(int j=0; j<tmp1.size(); ++j) if(!tmp1[j].type) bit.update(tmp1[j].id,-1);solve(tmp1,l,mid); solve(tmp2,mid+1,r);
}
vector <Node> tot;
int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin>>n>>q; bit.init(n+1);for(int i=1; i<=n; ++i){int val; cin>>val;tot.push_back({val,0,0,i,0});}for(int i=1; i<=q; ++i){int l, r, k; cin>>l>>r>>k;tot.push_back({l,r,k,i,1});}solve(tot,0,0x3f3f3f3f);for(int i=1; i<=q; ++i) cout<<ans[i]<<'\n';return 0;
}

有点小压行,不影响

我们看一下带修改的怎么写(树套树狗都不写)

就这个,唯一的区别是加了一个修改操做,我们加一个 \(type\) 表示修改

同理做就好

#include <bits/stdc++.h>
using namespace std;
const int MN=5e5+515;struct BIT{int tr[MN],n;int lowbit(int x){return x&-x;}void update(int x,int v){for(;x<=n;x+=lowbit(x)) tr[x]+=v;}int query(int x){int res=0;for(;x;x-=lowbit(x)) res+=tr[x];return res;}int query(int l,int r){return query(r)-query(l-1);}
}bit;struct Node{int x,y,k,id,type;};
int n,q,ans[MN],a[MN];
char op[MN];
vector<Node> qry;void solve(vector<Node> q,int l,int r){if(q.empty()) return;if(l==r){for(auto i:q) if(i.type==2) ans[i.id]=l;return;}int mid=(l+r)>>1;vector<Node> q1,q2;vector<pair<int,int>> hs;for(auto i:q){if(!i.type){if(i.x<=mid){bit.update(i.id,1);hs.emplace_back(i.id,1);q1.push_back(i);}else q2.push_back(i);}else if(i.type==1){if(i.y<=mid){bit.update(i.x,-1);hs.emplace_back(i.x,-1);q1.push_back(i);}else q2.push_back(i);}else{int res=bit.query(i.x,i.y);if(res>=i.k) q1.push_back(i);else i.k-=res,q2.push_back(i);}}for(auto [x,y]:hs) bit.update(x,-y);solve(q1,l,mid);solve(q2,mid+1,r);
}int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>q; bit.n=n;for(int i=1;i<=n;i++){cin>>a[i];qry.push_back({a[i],0,0,i,0});}for(int i=1;i<=q;i++){cin>>op[i];if(op[i]=='C'){int x,y;cin>>x>>y;qry.push_back({x,a[x],0,0,1});qry.push_back({y,0,0,x,0});a[x]=y;}else{int l,r,k;cin>>l>>r>>k;qry.push_back({l,r,k,i,2});}}solve(qry,0,1e9);for(int i=1;i<=q;i++) if(op[i]=='Q') cout<<ans[i]<<'\n';return 0;
}

再放一个吧......

这个大概说一下吧

题意就是我们有一个环(不会有我这样的弱智没有读出来吧),每个点属于一个国家,有一些操作,从 \(l\) 开始顺时针走一直到 \(r\) ,其中每一个点加上 \(v\) , 每一个国家有一个值,询问每个国家至少到什么时候才凑齐这个值

我们对于时间二分,使用差分+树状数组维护一下就行了

代码↓

#include <bits/stdc++.h>
using namespace std;
const int MN=3e5+315;
struct Add_Node{int l, r; long long val; int id;};
struct Query_Node{int id, val;};
int n, m;
long long ans[MN];
vector <int> sta[MN];
struct Bit{long long tr[MN];int lowbit(int x){return x&(-x);}void update(int pos, long long val){for(int i=pos; i<=m; i+=lowbit(i)) tr[i]+=val;}void update_range(int l, int r, long long val){update(l,val); update(r+1,-val);}int qval(long long pos){int res=0; for(int i=pos; i; i-=lowbit(i)) res+=tr[i];return res;}
}bit;
long long query(int x, int p){long long res=0;for(auto v:sta[x]){res+=bit.qval(v);if(res>=p) return -1;}return res;
}
void solve(vector <Add_Node> addtmp, vector <Query_Node> querytmp, int l, int r){if(l==r){for(auto v:querytmp) ans[v.id]=l;return;}int mid=(l+r)>>1;vector <Add_Node> addtmp_l, addtmp_r;vector <Query_Node> querytmp_l, querytmp_r;for(auto v:addtmp){if(v.id<=mid){if(v.l<=v.r){bit.update_range(v.l,v.r,v.val);}else{bit.update_range(v.l,m,v.val);bit.update_range(1,v.r,v.val);}addtmp_l.push_back(v);}else{addtmp_r.push_back(v);}}for(auto v:querytmp){int res=query(v.id,v.val);if(res==-1){querytmp_l.push_back(v);}else{v.val-=res;querytmp_r.push_back(v);}}for(auto v:addtmp_l){if(v.l<=v.r){bit.update_range(v.l,v.r,-v.val);}else{bit.update_range(v.l,m,-v.val);bit.update_range(1,v.r,-v.val);}    }solve(addtmp_l,querytmp_l,l,mid);solve(addtmp_r,querytmp_r,mid+1,r);
}
vector <Add_Node> addtot;
vector <Query_Node> querytot;
signed main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin>>n>>m;for(int i=1,val; i<=m; ++i){cin>>val; sta[val].push_back(i);}for(int i=1,val; i<=n; ++i){cin>>val; querytot.push_back({i,val});}int q; cin>>q;for(int i=1; i<=q; ++i){int l, r, val; cin>>l>>r>>val;addtot.push_back({l,r,val,i});}solve(addtot,querytot,1,q+1);for(int i=1; i<=n; ++i){if(ans[i]==q+1) cout<<"NIE\n";else cout<<ans[i]<<'\n';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何自做自己的网站网络设计开题报告

抽象节点这个特性自小程序基础库版本 1.9.6 开始支持。在组件中使用抽象节点有时&#xff0c;自定义组件模板中的一些节点&#xff0c;其对应的自定义组件不是由自定义组件本身确定的&#xff0c;而是自定义组件的调用者确定的。这时可以把这个节点声明为“抽象节点”。例如&am…

有什么网站可以做投票邯郸菜鸟网站建设

OD统一考试 题解&#xff1a; Java / Python / C 题目描述 一根X米长的树木&#xff0c;伐木工切割成不同长度的木材后进行交易&#xff0c;交易价格为每根木头长度的乘积。规定切割后的每根木头长度都为正整数,也可以不切割&#xff0c;直接拿整根树木进行交易。请问伐木工如…

响应网官方网站网站界面风格设计

1. 今日摸鱼计划 今天来学习一下ADC的原理&#xff0c;然后把ADC给实现 ADC芯片:ADC128S102 视频&#xff1a; 18A_基于SPI接口的ADC芯片功能和接口时序介绍_哔哩哔哩_bilibili 18B_使用线性序列机思路分析SPI接口的ADC芯片接口时序_哔哩哔哩_bilibili 18C_基于线性序列机的S…

量化投资 —— 实践

量化投资 —— 实践地址: https://item.taobao.com/item.htm?id=898078161839&mi_id=0000bSMU6-qva9mG_nEYyyLOcfGeJ5-tgwvwKtjY8IHE980&pvid=4580fb7a-c699-4f97-a5c0-8c810fa24035&scm=1007.40986.449…

详细介绍:性能优化 - 案例篇:缓存_Guava#LoadingCache设计

详细介绍:性能优化 - 案例篇:缓存_Guava#LoadingCache设计pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…

2025年X射线管厂家最新企业品牌推荐排行榜,工业用金属陶瓷,波长色散荧光分析,应力衍射分析,管板角焊缝,轮胎检测,辐照,固定阳极波纹陶瓷,测厚,食品检测 X 射线管公司推荐

在工业无损检测领域,X 射线管作为核心元件,其质量与性能直接影响检测结果的准确性和可靠性,对国防、石油、电力、汽车零部件等关键行业的发展至关重要。当前,市场上 X 射线管厂家数量众多,产品质量参差不齐,部分…

AtCoder Beginner Contest 400

AT_abc400_d [ABC400D] Takahashi the Wall Breaker 一次踢两步也转移一下,直接搜 E - Ringos Favorite Numbers 3

网站托管服务方案网站建设办公软件销售技巧

目录 1、进程的虚拟内存分区与小于0x10000的小地址内存区 1.1、进程的虚拟内存分区 1.2、小于0x10000的小地址内存区 2、保存线程上下文的CONTEXT结构体 3、从汇编代码角度去理解多线程运行过程的典型实例 4、调用TerminateThread强制结束线程会导致线程中的资源没有释放…

2025 年北京档案存放公司 升职猫档案服务平台:16 年老牌机构的合规服务与高效解决方案解析

档案管理作为衔接个人发展与社会管理的关键环节,其规范性与便捷性直接影响考公、考研、落户、评职称等重要人生节点。随着 2025 年档案管理服务市场规模迈向 2000 亿元,数字化转型与异地办事需求持续升温,政策推动下…

设计一个企业网站大概多少钱创新的南昌网站制作

一、结构体 结构体(struct)可以理解为用户自定义的特殊的复合的“数据类型”&#xff1b; 1. 结构体变量的定义和初始化 定义结构体变量的方式&#xff1a; 先声明结构体类型再定义变量名 在声明类型的同时定义变量 // 结构体类型的定义 struct stu {char name[50];int age;…

完整教程:⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践

完整教程:⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Cons…

没有网站可以做百度直通车吗自己主机做网站服务器吗

0x01 产品简介 企语iFair协同管理系统是一款专业的协同办公软件,该管理系统兼容性强,适合多种企业类型。该软件永久免费,绿色安全,无需收取费用即可使用所有功能。企语iFair协同管理系统同时兼容了Linux、Windows两种操作系统 0x02 漏洞概述 企语iFair协同管理系统getup…

[免费]微信小代码网上花店系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025电容厂家最新品牌推荐排行榜白皮书,固态,高压,牛角,安规,CBB,超级,红宝石电解,螺栓,超级电容推荐这十家公司!

在科技迭代日新月异的当下,电容作为电子设备的核心基础元件,其性能品质直接决定了终端产品的运行稳定性、使用寿命与功能上限。无论是消费电子领域的智能手机、笔记本电脑,工业场景中的医疗设备、智能工控系统,还是…

北京网站优化前景工业信息化部网站备案

hello&#xff0c;我是大千UI工场&#xff0c;本篇分享智慧安防的大屏设计&#xff0c;关注我们&#xff0c;学习N多UI干货&#xff0c;有设计需求&#xff0c;我们也可以接单。 实时监控与预警 可视化大屏可以将安防系统中的监控画面、报警信息、传感器数据等实时展示在大屏上…

帝国cms做企业网站大连制作网站公司

上文讲了《Linux进程在内核眼中是什么样子的&#xff1f;》&#xff0c;可以理解内核关于进程线程的所有管理就通过一个结构体 —— task_struct。知道了内核眼中进程的描述&#xff0c;本文通过三个例子站在用户态看下进程线程是如何创建的&#xff0c;不同的创建方式又有哪些…

深入解析:Guava限频器RateLimiter的使用示例

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025石材加工厂家最新品牌推荐排行榜:大祥工艺,业务覆盖东北,辽宁盖州,专业浮雕雕刻高级技师

石材加工行业在近年来呈现出快速发展的态势,但同时也面临着诸多问题。市场上石材加工企业数量众多,规模大小不一,导致产品质量参差不齐,部分企业为了追求短期利益,使用劣质原材料或简化加工工艺,使得石材产品的耐…

centos7升级降级内核 centos升级降级内核 centos升级内核 centos降级内核

centos7升级降级内核 centos升级降级内核 centos升级内核 centos降级内核# 强制安装旧版 kernel-headersrpm -ivh --force kernel*.el7.x86_64.rpm rpm -q kernel设置默认启动项 # 查看 GRUB 菜单中的名称awk -F\ /…

详细介绍:MySQL高可用集群

详细介绍:MySQL高可用集群2025-10-05 10:17 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; …