1. 程式人生 > >整體二分(模板) 求區間第k小

整體二分(模板) 求區間第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; }