/*划分树+二分,二分第k个数
题意:给一列数..若干个询问..问(l,r,h)...在[l,r]范围内..有多少个数小于等于h*/
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 100100
using namespace std;
int st[N],val[20][N],num[20][N];
void build(int x,int y,int cen)
{
if(x==y) return;
int mid=(x+y)>>1,i,l=x,r=mid+1,same=mid-x+1;
for(i=x;i<=y;i++)
if(val[cen][i]<st[mid])
same--;
for(i=x;i<=y;i++)
{
int flag=0;
if(val[cen][i]<st[mid]||(val[cen][i]==st[mid]&&same))
{
flag=1;
val[cen+1][l++]=val[cen][i];
if(val[cen][i]==st[mid])
same--;
}
else
{
val[cen+1][r++]=val[cen][i];
}
num[cen][i]=num[cen][i-1]+flag;
}
build(x,mid,cen+1);
build(mid+1,y,cen+1);
}
int query(int st,int ed,int k,int x,int y,int cen)
{
if(x==y) return val[cen][x];
int mid=(x+y)>>1;
int lx=num[cen][st-1]-num[cen][x-1];
int ly=num[cen][ed]-num[cen][st-1];
int rx=st-1-x+1-lx;
int ry=ed-st+1-ly;
if(k<=ly)
return query(x+lx,x+lx+ly-1,k,x,mid,cen+1);
else
{
st=mid+rx+1;
ed=mid+rx+ry;
return query(st,ed,k-ly,mid+1,y,cen+1);
}
}
int main()
{
int t,n,m,i,j,k,l,r,ans,mid,a,cnt=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(num,0,sizeof(num));
for(i=1;i<=n;i++)
{
scanf("%d",&st[i]);
val[0][i]=st[i];
}
sort(st+1,st+1+n);
build(1,n,0);
printf("Case %d:\n",cnt++);
while(m--)
{
scanf("%d%d%d",&i,&j,&k);
i++; j++;
l=1; r=j-i+1; ans=0;
while(l<=r)
{
mid=(l+r)>>1;
a=query(i,j,mid,1,n,0);
if(a<=k)
{
l=mid+1;
ans=mid;
}
else
r=mid-1;
}
printf("%d\n",ans);
}
}
return 0;
}
hdu 4417 划分树+二分
最新推荐文章于 2021-02-19 12:06:15 发布