整体二分模板
静态区间第\(k\)大
总结:码量小,感觉比较好写,常数优秀,大约是主席树的1.5倍速度左右。
Code:
#include <cstdio>
#include <algorithm>
const int N=2e5+10;
struct node{int l,r,k,id;}qry[N<<1],ql[N<<1],qr[N<<1];
int n,m,ans[N],b[N],s[N];
void add(int x,int d){while(x<=n)s[x]+=d,x+=x&-x;}
int query(int x){int sum=0;while(x)sum+=s[x],x-=x&-x;return sum;}
void divide(int l,int r,int s,int t)
{
if(s>t) return;
if(l==r)
{
for(int i=s;i<=t;i++) ans[qry[i].id]=b[l];
return;
}
int mid=l+r>>1,lp=0,rp=0;
for(int i=s;i<=t;i++)
if(!qry[i].id)
{
if(qry[i].k<=mid) add(qry[i].l,1),ql[++lp]=qry[i];
else qr[++rp]=qry[i];
}
for(int i=s;i<=t;i++)
if(qry[i].id)
{
int c=query(qry[i].r)-query(qry[i].l-1);
if(c>=qry[i].k) ql[++lp]=qry[i];
else qr[++rp]=qry[i],qr[rp].k-=c;
}
for(int i=s;i<=t;i++)
if(!qry[i].id&&qry[i].k<=mid)
add(qry[i].l,-1);
for(int i=s;i<=s+lp-1;i++) qry[i]=ql[i+1-s];
for(int i=s+lp;i<=t;i++) qry[i]=qr[i+1-s-lp];
divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&qry[i].k),b[i]=qry[i].k,qry[i].l=i;
std::sort(b+1,b+1+n);
int cnt=std::unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) qry[i].k=std::lower_bound(b+1,b+1+cnt,qry[i].k)-b;
for(int i=1;i<=m;i++) scanf("%d%d%d",&qry[i+n].l,&qry[i+n].r,&qry[i+n].k),qry[i+n].id=i;
divide(1,cnt,1,n+m);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}
2018.10.31