整体二分乱扯

前言

  • msjing现在好饿啊啊啊啊啊

整体二分

  • 这个东东是怎么来的捏
  • 由于一些题目经常把询问每个都二分卡爆,所以可以依据询问的关联性直接将多个二分合并为一个
  • 很吊对不对,但是msjing真的很饿
  • 这个东西是离线的哦

操作与使用

  • 整体二分一般是多个询问并行的查询方法,结合例题看看

例题P3834 【模板】可持久化线段树 2

  • 欸,我们直接用主席树创过去
  • 我们考虑朴素做法
  • 常规来说单查区间第 \(k\) 大二分就可以,但是现在是多次询问,复杂度飞起来
  • 所以我们采用整体二分
  • 那么我们就找到了整体二分的使用条件

1.询问可二分
2.修改之间互不影响
3.离线

  • 说白了就是可以单个二分且每次二分互不影响就可以整体
  • 那我们说一下怎么做
    • 把操作(这题没操作,但是后面都这么说)和区间全读进去
    • 开始二分,对于操作,判位置与 \(mid\) 关系,小于等于向左,大于向右
    • 对于查询,也与 \(mid\) 比较,此时需要转化,对于所查区间,若这个区间内的数大于等于 \(k\),证明左区间够用,向左,否则向右,区间个数可以用 \(BIT\) 维护
    • 当到达叶子节点时,直接把 \(l\) 加入答案(因为二分的是答案)
  • 就没了
  • 实现的话由于讲课的博客写的是 vector,但msjing是个毒瘤用的是数组,e,其实是贺的
点击查看代码
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=5e5+10,inf=0x7f7f7f7f;
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
    {
        if (ch == '-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        x=(x<<1)+(x<<3)+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int n,m,a[maxn],ans[maxn];
int tot;
struct __ {int x,y,k,id,op;}q[maxn],q1[maxn],q2[maxn];
struct BIT
{
    int c[maxn];
    int lb(int x) {return x&(-x);}
    void add(int x,int v) {while (x<=n) c[x]+=v,x+=lb(x);}
    int que(int x)
    {
        int res=0;
        while (x)
        {
            res+=c[x];
            x-=lb(x);
        }
        return res;
    }
}BT;
void sol(int L,int R,int l,int r)
{
    if (L>R) return;
    if (l == r)
    {
        for (int i=L;i<=R;i++) if (q[i].op == 2) ans[q[i].id]=l;
        return;
    }
    int mid=(l+r) >> 1;
    int t1=0,t2=0;
    for (int i=L;i<=R;i++)
    {
        if (q[i].op == 1)
        {
            if (q[i].x<=mid) BT.add(q[i].id,1),q1[++t1]=q[i];
            else q2[++t2]=q[i];
        }
        else
        {
            int res=BT.que(q[i].y)-BT.que(q[i].x-1);
            if (res>=q[i].k) q1[++t1]=q[i];
            else q[i].k-=res,q2[++t2]=q[i];
        }
    }
    for (int i=1;i<=t1;i++) if (q1[i].op == 1) BT.add(q1[i].id,-1);
    for (int i=1;i<=t1;i++) q[i+L-1]=q1[i];
    for (int i=1;i<=t2;i++) q[i+L+t1-1]=q2[i];
    sol(L,L+t1-1,l,mid),sol(L+t1,R,mid+1,r);
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=n;i++)
    {
        int x=read();
        q[++tot]={x,1,(int)1e9,i,1};
    }
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read(),k=read();
        q[++tot]={x,y,k,i,2};
    }
    sol(1,tot,(int)-1e9,(int)1e9);
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
  • 但是msjing真的好饿啊啊啊啊啊

进阶

  • msjing改红温了,全咕🤣

批注 2026-07-23 145257

后话

  • e,这个坑就撂这先不填了,什么时候有精力了再说
  • 晶石候任:一定要学 vector 做法不然会非常红
posted @ 2026-07-23 14:12  msjing  阅读(6)  评论(0)    收藏  举报