码迷,mamicode.com
首页 > 其他好文 > 详细

整体二分

时间:2019-03-17 15:38:51      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:val   include   题意   algo   else   更新   pac   names   ==   

A.求区间第 \(k\) 大数

整体二分的思想其实和cdq分治有一点相似之处。
具体操作:

def q[],q1[],q2[],cnt1,cnt2

solve(l,r,val_l,val_r){

if val_l==val_r
    将所有[l,r]中的q中的询问答案设为val_l,return

for i in [l,r]
    if q[i]是修改操作
        更新树状数组 位置:q[i].pos 值:q[i].val
        q1[++cnt1]=q[i]
    else
        q2[++cnt2]=q[i]

将树状数组中所有操作撤销
将q1,q2中的操作复制到q中
设mid=(val_l+val_r)/2
solve(l,l+cnt1-1,val_l,mid)
solve(l+cnt1,r,mid+1,val_r)

}

Code

#include<cstdio>
#include<algorithm>
#define maxn 200003
#define INF 1050000000
using namespace std;
struct T{
    int mo,l,r,k,num;
    T(){}
    T(int _mo,int _l,int _r,int _k,int _num):mo(_mo),l(_l),r(_r),k(_k),num(_num){}
}q[maxn],ql[maxn],qr[maxn];
int t[maxn],n,m,ANS[maxn];
void add(int pos,int k){while(pos<=n)t[pos]+=k,pos+=pos&-pos;}
int query(int pos){int ret=0;while(pos)ret+=t[pos],pos-=pos&-pos;return ret;}
void bin(int l,int r,int val_l,int val_r){
    if(l>r)return;
    if(val_l==val_r){
        for(int i=l;i<=r;i++){
            if(q[i].mo==2)ANS[q[i].num]=val_l;
        }
        return;
    }
    int cntl=0,cntr=0,val_mid=(val_l+val_r)>>1;
    for(int i=l;i<=r;i++){
        if(q[i].mo==1){
            if(q[i].k<=val_mid){
                add(q[i].num,1);
                ql[++cntl]=q[i];
            }
            else{
                qr[++cntr]=q[i];
            }
        }
        else{
            int tmp=query(q[i].r)-query(q[i].l-1);
            if(q[i].k<=tmp){
                ql[++cntl]=q[i];
            }
            else{
                q[i].k-=tmp;
                qr[++cntr]=q[i];
            }
        }
    }
    for(int i=1;i<=cntl;i++){
        if(ql[i].mo==1)add(ql[i].num,-1);
    }
    for(int i=1;i<=cntl;i++){
        q[l+i-1]=ql[i];
    }
    for(int i=1;i<=cntr;i++){
        q[l+i+cntl-1]=qr[i];
    }
    bin(l,l+cntl-1,val_l,val_mid);
    bin(l+cntl,r,val_mid+1,val_r);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int a;
        scanf("%d",&a);
        q[i]=T(1,0,0,a,i);
    }
    for(int i=1;i<=m;i++){
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        q[i+n]=T(2,x,y,k,i);
    }
    bin(1,n+m,-INF,INF);
    for(int i=1;i<=m;i++)printf("%d\n",ANS[i]);
    return 0;
}

B.区间 \(k\) 大数带修改

一样的,把修改操作视为先删除再插入。

C.区间 \(k\) 大数带插入

题意

\(N\) 个桶,每次操作是将 \([l,r]\) 中的每个桶加入一个树,求区间 \(k\) 大数。

一样的,没有任何区别。

整体二分

标签:val   include   题意   algo   else   更新   pac   names   ==   

原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/10547069.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!