首页 > 其他分享 >整体二分

整体二分

时间:2024-04-20 21:23:28浏览次数:18  
标签:二分 数组 .. int 询问 整体 mid 答案

主要思想:把多个询问一起解决(一次二分同时处理多个询问,确实顾名思义)

记 \([l,r]\) 为答案的值域,\([L,R]\) 为答案的定义域,\(mid=(l+r)/2\)。(也就是说求答案时仅考虑下标在 \([L,R]\) 内的操作和询问,这其中询问 的答案在 \([l,r]\) 内)

  • 我们首先把所有操作 按时间顺序 存入数组中,然后开始分治。
  • 在每一层分治中,利用数据结构(常见的是树状数组)统计 当前查询(即 \([L..R]\) 内的所有查询)的答案 和 \(mid\) 之间的关系。
  • 我们已经通过这个数据结构知道了 当前所有 \([L..R]\) 内的查询 的答案 与 \(mid\) 之间的大小关系,然后我们根据 \([L..R]\) 内查询 的答案小于等于 \(mid\) 和大于 \(mid\) 两种关系,把查询分成 \(q1\) 和 \(q2\) 两份,并分别递归处理。(这样保证了问题量确实在缩小)
  • 当 \(l=r\) 时,找到答案,记录答案并返回即可。

需要注意的是,在整体二分过程中,若当前处理的答案值域为 \([l,r]\),则此时最终答案范围不在 \([l,r]\) 的询问会在其他时候处理

时间复杂度:

首先若不考虑有若干个询问,则分治复杂度只与答案值域 或 答案可能的取值集合大小 \(V\) 有关,最多递归 \(\log V\) 层;每层一共处理 \(m\) 个询问,故复杂度 \(\mathcal O(n\log V)\).

若内部用了额外复杂度 \(\mathcal O(m)\) 的数据结构,则总复杂度 \(\mathcal O(nm\log V)\).

适用范围:

  1. 询问的答案单次可二分
  2. 修改对判定答案的贡献互相独立,修改之间互不影响效果
  3. 修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值
  4. 贡献满足交换律,结合律,具有可加性
  5. 题目允许离线

多次询问区间第 k 小

把 \(a\) 数组排序得到 \(b\) 数组,同时记录 \(b\) 在 \(a\) 中的原编号

这样 \(V\) 缩小到了 \(n\) 级别,\(l,r,mid\) 变成了代表 \(b_l,b_r,b_{mid}\)

如何判定 \([L..R]\) 的询问的答案 与 答案 \(b_{mid}\) 的大小关系?

把 \(b_l..b_{mid}\) 按下标加入到树状数组中,对于询问 \([l_i,r_i,k_i]\),树状数组可以回答下标 \([l_i..r_i]\) 中有多少 小于等于 \(b_{mid}\) 的数,这样就解决了问题

静态区间第 k 小的代码解释

王队的代码:

#include<bits/stdc++.h>

using namespace std;

inline int read(){
    int x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x;
}

const int N=5e5+5;
int n,m,a[N];
struct Ques{int l,r,k,id;};
int tr[N],ans[N];
void add(int x,int v){
    for(;x<=n;x+=x&-x) tr[x]+=v;
}
int qry(int x){
    int res=0;
    for(;x;x-=x&-x) res+=tr[x];
    return res;
}

Ques lq[N*2],tql[N*2],tqr[N*2];
void dac(int ql,int qr,int l,int r){
    if(ql>qr) return ;
    if(l==r){
        for(int i=ql;i<=qr;++i){
            Ques q=lq[i];
            ans[q.id]=l;
        }
        return ;
    }
    int cl=0,cr=0;
    int mid=(l+r)>>1;
    for(int i=ql;i<=qr;++i){
        Ques q=lq[i];
        if(!q.id){
            if(q.k<=mid) add(q.l,1),tql[++cl]=q;
            else tqr[++cr]=q;
        }else{
            int num=qry(q.r)-qry(q.l-1);
            if(q.k<=num) tql[++cl]=q;
            else q.k-=num,tqr[++cr]=q;
        }
    }
    for(int i=ql;i<=qr;++i){
        Ques q=lq[i];
        if(!q.id){
            if(q.k<=mid) add(q.l,-1);
        }else break;
    }
    for(int i=1;i<=cl;++i) lq[ql+i-1]=tql[i];
    for(int i=1;i<=cr;++i) lq[ql+cl+i-1]=tqr[i];
    dac(ql,ql+cl-1,l,mid),dac(ql+cl,qr,mid+1,r);
}

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i) lq[i]={i,i,read(),0};
    for(int i=1;i<=m;++i){
        int l=read(),r=read(),k=read();
        lq[i+n]={l,r,k,i};
    }
    dac(1,n+m,1,n);
    for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
    return 0;
}

解释:

把读入 \(a_i\) 当作在时间 \(i\) 进行插入操作,则一共 \(n+m\) 个操作和询问,对他们整体二分

则 \([L..R]\) 表示处理时间 \([L..R]\) 的操作和询问,由于题目保证 \(1\le a_i\le n\),故 \([l..r]\) 直接表示的是答案区间

对于插入操作,我们只处理 插入值 \(\le k\) 的操作(加到树状数组上),同时按插入值把插入操作分类

对于询问,同样的分类

为什么在还原树状数组时可以 else break 呢?因为操作从始至终都在询问之前

带修

把修改看成删除(树状数组上该位置 \(-1\))再插入(\(+1\))

对于答案 \(mid\):

  • 修改:分类;若修改值 \(\le mid\),在树状数组上同步修改
  • 询问:查出 \([l..r]\) 内 \(\le mid\) 的数量,类似的分类

一个 idea

每次二分,calc(x) 的时候 \(x\) 的变化量每次减半,若每次重新 calc 一遍就太浪费了

我们按变化量一个一个的看他对 calc 值的改变

变化量加起来是 \(\mathcal O(V)\) 的

标签:二分,数组,..,int,询问,整体,mid,答案
From: https://www.cnblogs.com/laijinyi/p/18148187

相关文章

  • 如何使用鞋厂ERP等企业管理软件提高企业运营整体效率?
    ERP把企业客户需求、市场规划、产品研发、内部制造等活动以及供应商的资源整合在一起,形成企业一个完整的产业链和供应链,通过企业多个环节的无缝链接和整体运作来提高企业运营整体效率:(1) . 对整个产业链和供应链资源进行管理;  (2) . 迭代研发、精益生产、敏捷制造和同......
  • python --二分法学习
    deffound_number(need_vaule,l):print(l)mid_index=len(l)//2mid_value=l[mid_index]print("mid_valueis%s"%(mid_value))ifmid_value>need_vaule:l=l[:mid_index]print('needtofind1')......
  • [dp 小计] wqs 二分
    天才算法!国外叫Alienstrick(外星人trick),真的太强了。其实是因为IOI2016Aliens这道题考了这个算法才开始普及。解决问题wqs二分一般用来解决如下问题。给定\(n\)个数,求强制选\(m\)个的价值最大。如果不是强制选\(m\)个,这类问题很好做。现在问题就是怎么取消......
  • 动态规划、回溯、BFS、二分、滑动窗口总结
    动态规划动态规划的核心问题:重叠子问题,最优子结构,状态转移方程动态规划与记忆递归的区别:记忆递归为自顶而上的递归剪枝,动态规划为自底向上的循环迭代;正确的状态转移方程+dp[]数组:确定状态(原问题和子问题中变化的变量)->确定dp数组的定义dp[i]->确定当前状态的'选择'并确定......
  • 二分图性质
    二分图独立集定义:在二分图\(G\)中选出点集\(S\)使得点集\(S\)中的点两两之间没有边相连。二分图最大独立集定义:在二分图\(G\)中选出点集\(S\)使得点集\(S\)中的点两两之间没有边相连,且使得不存在另一个二分图独立集\(S'\)使得\(|S'|>|S|\)。二分图最大独立集\(......
  • 认识什么是LLM、RAG、LangChain以及开发LLM应用的整体流程?
    认识大语言模型LLM时间:2024-04-15,星期一一、大型语言模型(LLM)理论简介大语言模型(LLM)的概念⼤语⾔模型(LLM,LargeLanguageModel),也称⼤型语⾔模型,是⼀种旨在理解和⽣成⼈类语⾔的⼈⼯智能模型。LLM的发展历程20世纪90年代,统计学习⽅法来预测词汇2003年深度学习先驱B......
  • 「二分图」笔记
    二分图同时满足不存在奇数环和染色法不矛盾。二分图的判定:染色法#include<bits/stdc++.h>usingnamespacestd;constintN=1e3+10,M=2e6+10;struct{ intto,next;}e[M];inttop,h[N],color[N],n,m;voidadd(intx,inty){ e[++top]={y,h[x]};......
  • 【二分+容斥】【ST表/单调栈】【划分型DP】
    二分+容斥题目链接https://leetcode.cn/problems/kth-smallest-amount-with-single-denomination-combination/description/题目大意题目思路假设有一个x元硬币思考只有一种面额为3的硬币时,3可以组成不超过x的面额的数量有x/3种!思考有两种面额【3,6】,可以组成不......
  • 蓝桥杯-跳石头(二分法)
    0.题目题目描述一年一度的「跳石头」比赛又要开始了!这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有N块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至......
  • WQS 二分
    一个参考WQS二分用来处理一些答案构成凸函数的问题。最经典、最常见的形式,就是"从若干个物品中恰好选给定个数的最优"型问题。适用要求:如果不考虑选的物品的个数限制,可以很快求出答案。例题:P2619TreeI从所有白边中选\(need\)条,然后加上若干条黑边形成生成树,最优是多......