【题目大意】
给出一个长度为n的序列和m组查询(i,j,k),输出[i,j]中的第k大数。
【思路】
先离散化然后莫队分块。用树状数组来维护当前每个值的个数,然后对于每次询问二分答案即可。
又一次实力写错二分…(生无可恋脸.jpg)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=+;
const int MAXM=+;
struct node
{
int l,r,k,pos,id,ans;
}q[MAXM];
bool cmp(node x,node y)
{
return (x.pos==y.pos)?x.r<y.r:x.pos<y.pos;
}
bool cmpid(node x,node y)
{
return (x.id<y.id);
}
struct discretize
{
int num,pos;
bool operator < (const discretize &x) const {return (num<x.num);}
}tmp[MAXN];
int n,m;
int a[MAXN],e[MAXN];
int ori[MAXN];//离散化后的i对应的原数字为ori[i] int lowbit(int x)
{
return (x&(-x));
} void modify(int p,int x)
{
while (p<=n)
{
e[p]+=x;
p+=lowbit(p);
}
} int sum(int p)
{
int ret=;
while (p>)
{
ret+=e[p];
p-=lowbit(p);
}
return ret;
} void init()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
{
scanf("%d",&tmp[i].num);
tmp[i].pos=i;
}
sort(tmp+,tmp+n+);
for (int i=,j=;i<=n;i++)
{
if (i== || tmp[i].num!=tmp[i-].num) ++j,ori[j]=tmp[i].num;
a[tmp[i].pos]=j;
}
int block=(int)sqrt(n);
for (int i=;i<=m;i++)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
q[i].id=i;
q[i].pos=(q[i].l-)/block+;
}
sort(q+,q+m+,cmp);
} int binary_search(int k)
{
int lb=,ub=n;
while (ub-lb>)
{
int mid=(ub+lb)>>;
if (sum(mid)>=k) ub=mid;else lb=mid;//注意一下二分怎么写
}
return ub;
} void solve()
{
int l=,r=;
memset(e,,sizeof(e));
for (int i=;i<=m;i++)
{
while (l<q[i].l) modify(a[l],-),l++;
while (l>q[i].l) l--,modify(a[l],);
while (r<q[i].r) r++,modify(a[r],);
while (r>q[i].r) modify(a[r],-),r--;
q[i].ans=binary_search(q[i].k);
}
sort(q,q+m+,cmpid);
for (int i=;i<=m;i++) printf("%d\n",ori[q[i].ans]);
} int main()
{
init();
solve();
return ;
}