当前位置: 首页 > news >正文

整体二分

前言

注意:以下的 “元素” 都代表原题中的一个操作。

大说

把当前值域一分为二,把当前元素集合,每个元素的决策只有左区间 or 右区间,可以把同决策的元素放在一起去分治子区间(类似于线段树的结构)。

如下图(左边是值域区间,右边是元素集合):


上图每个询问的答案:

①:2

②:2

③:4

④:9

⑤:6

⑥:10

中说

那么怎么给元素们分决策呢?

首先我们二分值域区间,那么肯定有一个 \(mid\)

然后我们用 \(f(mid,i)\)\(g(i)\) 比较来进行分配 \(i\) 元素去处。

以区间第 k 大举例:

一个元素 \(i\) 包含 \(l_i、r_i、k_i\),表示询问 \([l_i,r_i]\) 中第 \(k_i\) 大的数。

\(f(mid,i)\) 就是 \(mid\)\([l_i,r_i]\) 区间有多少个数比他小。

\(g(i)\) 就是 \(k_i\)

如果前者大,那么值域区间肯定为 \([l,mid]\),决策至左。

如果后者大,那么值域区间肯定为 \([mid+1,r]\),决策至右。

小说:

【模板】带修整体二分

  • 修改和询问一起放在元素集合里就行,修改如询问一般决策,所以这两个我都称作元素。

  • 若询问元素决策到 \([mid+1,r]\) ,那么 \(k_i-=g(i)\),因为关于 \(g(i)\) 的修改都决策到 \([l,mid]\) 了。

  • 遇到修改就修改,遇到询问就询问。在顺序把每个元素决策到两个子区间时,子区间内各元素之间不会改变相对位置,所以可以带修。

#include<bits/stdc++.h>
using namespace std;
const int QAQ=510000;
int s[QAQ],n,m,ans[QAQ],cnt,shang[QAQ],a[QAQ];
int lbd(int x) {return (x&(-x));}
void gai(int x,int c) {for(int i=x;i<=n;i+=lbd(i)) s[i]+=c;}
int cha(int x) {int da=0;for(int i=x;i;i-=lbd(i)) da+=s[i];return da;}
char op;
struct xxx {int op,id,x,y,k;} q[QAQ],q1[QAQ],q2[QAQ];
void work(int l,int r,int ql,int qr)
{if(ql>qr) return ;if(l==r) {for(int i=ql;i<=qr;i++) if(q[i].op==0) ans[q[i].id]=l;return ;}int o1=0,o2=0,mid=(l+r)>>1;for(int i=ql;i<=qr;i++)if(q[i].op==0){int pai=cha(q[i].y)-cha(q[i].x-1);if(q[i].k<=pai) q1[++o1]=q[i];else q[i].k-=pai,q2[++o2]=q[i];}else{if(q[i].y<=mid) q1[++o1]=q[i],gai(q[i].x,q[i].k);else q2[++o2]=q[i];}for(int i=1;i<=o1;i++) if(q1[i].op) gai(q1[i].x,-q1[i].k);for(int i=1;i<=o1;i++) q[ql+i-1]=q1[i];for(int i=1;i<=o2;i++) q[ql+o1+i-1]=q2[i];work(l,mid,ql,ql+o1-1),work(mid+1,r,ql+o1,qr);
}
int main()
{cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i],q[++cnt]={1,114514,i,a[i],1},shang[i]=a[i];for(int i=1,l,r,k,x,y;i<=m;i++){ans[i]=-114514,cin>>op;if(op=='Q') cin>>l>>r>>k,q[++cnt]={0,i,l,r,k};else cin>>x>>y,q[++cnt]={1,114514,x,shang[x],-1},q[++cnt]={1,114514,x,y,1},shang[x]=y;}work(0,1000000000,1,cnt);for(int i=1;i<=m;i++) if(ans[i]!=-114514) cout<<ans[i]<<'\n';return 0;
}

复杂度

可以发现多个二分答案的路径不过是 \(V log V\) 种,但是我只走 \(q\) 个路径所以我普通二分是 \(q log V\) 种路径都走一遍,但是我整体二分相当于路径重复的可以不算,所以可以想到用极限法证明:

极限法:所有点相距都一样远,并且尽可能地远,这样路径重复最少,是整体二分最绝望的时刻。

\(T(q,V)\)\(q\) 个元素,\(V\) 大的值域的时间复杂度。

\(c(q)\) 是当前有 \(q\) 个元素继续分组分治花费的时间复杂度。

\(T(q,V)=2T(q/2,V/2)+c(q)\)

\(T(q,V)=\sum _{i}2^ic(\dfrac{q}{2^{i}})\)

\(T(q,V)≈\sum _{i}c(q)\) —— 因为 \(c(q)\) 一般是 \(q\log q\) 或者 \(q\),所以可以这么算。

\([T(q,V)]_{max}=c(q)\log V\)

再看看此时二分什么复杂度:\(O(q·c(1)\log V)\) ,有时二分的 \(c(1)\) 的复杂度有时改得更快(如简单二分的 \(c(1)\)\(O(1)\) 的,这时二分是 \(O(qlog V)\),但是感觉整体二分在所有查询一起查询时更牛王。

http://www.hskmm.com/?act=detail&tid=7605

相关文章:

  • 得力 - Bruce
  • 短视频营销运营导师张伽赫,绳木传媒AI+短视频引领企业数字化变革
  • 详细介绍:还在重启应用改 Topic?Spring Boot 动态 Kafka 消费的“终极形态”
  • 用 TensorFlow 和 CNN 实现验证码识别
  • 用 PyTorch 和 CNN 进行验证码识别
  • 用 Keras 和 CNN 进行验证码识别
  • 从 Bank Conflict 数学表示看 Buffer 设计 Trade-Off
  • 被彼此笼罩 任泪水将我们缠绕 深陷入恶魔的拥抱 在阴冷黑暗处灼烧 吞下这毒药
  • mysql无法连接服务器的mysql #mysql8
  • DAG 最小路径覆盖问题 笔记
  • SP3D c# 开发独立的exe
  • python错误code
  • 瑞 ping 我
  • java八股文笔记 - 指南
  • NOIP 模拟赛十六
  • 【AT_dp_y】Grid 2 - Harvey
  • C#十五天 026多态重写 027抽象类与开闭原则 028接口,依赖反转,单元测试
  • 解题报告-P11844 [USACO25FEB] Friendship Editing G
  • lc1030-距离顺序排列矩阵单元格
  • 这是一个核弹
  • 【abc180F】Unbranched - Harvey
  • 合并区间-leetcode
  • 两种判断计算机大小端模式的方法
  • ROS2之节点
  • 9.17日总结
  • ECT-OS-JiuHuaShan 框架,元推理AGI奇迹
  • Mapper与Mapper.xml的关系
  • Rocky Linux10.0安装zabbix7.4详细步骤 - 教程
  • 【P3158】放棋子 - Harvey
  • 最强AI语音克隆和文本配音工具!与真人无异,CosyVoice下载介绍