整体二分(模板) 求区间第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;
}