整体二分(模板) 求区间第k小

整体二分,将询问与初值一起放入一个结构体里,然后每次二分判断询问在哪边,树状数组维护,时间复杂度O((n+Q)lognlogMAX_a[i]

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
const int MAXN = 200005;
const int inf = 1e9+1;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=ch=='-'?-1:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct Data{
    int x,y,k,id,type;
}data[MAXN<<1],q1[MAXN<<1],q2[MAXN<<1];

int n,m,cnt;
int ans[MAXN],f[MAXN];

inline void update(int x,int w){
    for(;x<=n;x+=x&-x) f[x]+=w;
}

inline int query(int x){
    int ret=0;
    for(;x;x-=x&-x) ret+=f[x];
    return ret;
}

void Solve(int ql,int qr,int l,int r){
    if(ql>qr) return;
    if(l==r){
        for(register int i=ql;i<=qr;i++)
            if(data[i].type==2) ans[data[i].id]=l;
        return;
    } 
    int mid=l+r>>1,p1=0,p2=0;
    for(register int i=ql;i<=qr;i++){
        if(data[i].type==1){
            if(data[i].x<=mid) {
                q1[++p1]=data[i];
                update(data[i].id,1);
            }else q2[++p2]=data[i];
        }
        else {
            int res=query(data[i].y)-query(data[i].x-1);
            if(res>=data[i].k) q1[++p1]=data[i];
            else{
                data[i].k-=res;
                q2[++p2]=data[i];
            }
        }
    }
    for(register int i=1;i<=p1;i++)
        if(q1[i].type==1) update(q1[i].id,-1);
    for(register int i=1;i<=p1;i++) data[i+ql-1]=q1[i];
    for(register int i=1;i<=p2;i++) data[i+ql+p1-1]=q2[i];
    Solve(ql,ql+p1-1,l,mid);Solve(ql+p1,qr,mid+1,r);
}

int main(){
    n=rd();m=rd();
    for(register int i=1;i<=n;i++) data[++cnt]=Data{rd(),1,inf,i,1};
    for(register int i=1;i<=m;i++) data[++cnt]=Data{rd(),rd(),rd(),i,2};
    Solve(1,cnt,-inf,inf);
    for(register int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40448823/article/details/81710459