整体二分好喵喵~长得很像决策单调性的分治优化,它能够帮助你不用写各种树套主席树就能很轻易地求出第k小数233333(大雾

  首先确定一个决策区间solve(l, r, L, R)表示编号在L~R的操作的数的权值和询问的答案在l~r这个区间,每次将答案二分,把L~R里的修改操作按被修改数的权值<=mid和>mid分成左右两边,如果<=mid,就把它下标所在位置在bit里+1,把L~R里的查询操作按bit上查询区间里的sum>=k和<k分成左右两边,如果<k,那么k就要减去bit上查询区间里的sum,然后就按丢到左右两边的操作分治就好了。

  应该还是不难理解的,虽然将操作和询问分成左右两边修改了原顺序,但是会互相影响的操作之间一定是按原顺序进行的,因为修改的排名大的数对排名小的数无影响,先处理答案小的,所以处理答案大的时候k已经减去了答案小的时候的贡献,于是处理答案大的区间的时候实际也不受到答案小的区间的影响,这样就能做到一层O(N),一共log(N)层,加上bit复杂度log(N),总复杂度O(Nlog^2N)。

整体二分的具体流程:

void solve(int l, int r, int L, int R)
{
    if(l>r || L>R) return;
    if(l==r) 
    {
        for(int i=L;i<=R;i++) if(q[i].ty) ans[q[i].pos]=l; //如果q[i].ty==1是询问,就把答案丢进去 
        return;
    }
    int mid=(l+r)>>1, cnt1=0, cnt2=0; //二分答案 
    for(int i=L;i<=R;i++)
    if(q[i].ty)
    {
        int tmp=query(q[i].y)-query(q[i].x-1); //求bit上询问区间的sum
        if(tmp>=q[i].k) q1[++cnt1]=q[i]; //<=k就丢左边
        else q[i].k-=tmp, q2[++cnt2]=q[i]; //>k就更新k后丢右边 
    }
    else
    {
        if(q[i].x<=mid) add(q[i].pos, q[i].y), q1[++cnt1]=q[i]; //如果被修改数<=mid,就更新bit并丢到左边
        else q2[++cnt2]=q[i]; 
    }
    for(int i=1;i<=cnt1;i++) if(!q1[i].ty) add(q1[i].pos, -q1[i].y); //如果是修改,删去在bit上的值
    for(int i=1;i<=cnt1;i++) q[L+i-1]=q1[i]; //丢到左边~ 
    for(int i=1;i<=cnt2;i++) q[L+cnt1+i-1]=q2[i]; //丢到右边~ 
    solve(l, mid, L, L+cnt1-1); solve(mid+1, r, L+cnt1, R); //分治~ 
}
View Code

相关文章:

  • 2021-12-10
  • 2022-01-04
  • 2022-12-23
  • 2022-01-28
  • 2021-08-09
  • 2021-07-31
  • 2022-03-02
猜你喜欢
  • 2021-08-17
  • 2018-08-27
  • 2021-10-14
  • 2021-07-13
  • 2021-07-15
  • 2021-12-17
相关资源
相似解决方案