#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#include <queue> //hdu4417(划分树)--二分
#define N 100010
using namespace std;
int sorted[N], p[20][N], num[20][N];
void build(int l, int r, int n)
{
if(l==r)return ;
int t, count, lr=l, mid, rh;
mid=(l+r)>>1;
rh=mid+1;
for(t=mid, count=0; t>=l; --t)
{
if(sorted[mid]==sorted[t])
count++;
else break;
}
for(t=l; t<=r; ++t)
{
num[n][t]=num[n][t-1];
if(p[n][t]==sorted[mid])
{
if(count)
{
count--;
p[n+1][lr++]=p[n][t];
num[n][t]++;
}
else
{
p[n+1][rh++]=p[n][t];
}
}
else if(p[n][t]<sorted[mid])
{
p[n+1][lr++]=p[n][t];
num[n][t]++;
}
else p[n+1][rh++]=p[n][t];
}
build(l, mid, n+1);
build(mid+1, r, n+1);
return ;
}
int query(int n, int l, int r, int ql, int qr, int k) //求在[ql,qr]内第k小的数
{
if(l==r)return p[n][l];
int s=0, s1, s2, s3, mid;
mid=(l+r)>>1;
s1=num[n][qr]-num[n][ql-1]; //[ql,qr]左孩子的个数
s2=num[n][ql-1]-num[n][l-1]; //[l,ql)左孩子的个数
if(k<=s1)
{
return query(n+1, l, mid, l+s2, l+s1+s2-1, k);
}
else
{
s2=ql-l-s2; //[l,ql)右孩子的个数
s3=qr-ql+1-s1; //[ql,qr]右孩子的个数
return query(n+1, mid+1, r, mid+1+s2, mid+s2+s3, k-s1);
}
}
int solve(int a, int b, int c, int n) //二分
{
int l=1, r=b-a+1, mid, ans=0, k; //r是这个区间的长度,二分是按在这个区间(a,b)内第几小(名次)来二分的
while(l<=r)
{
mid=(l+r)>>1;
k=query(0, 1, n, a, b, mid); //k第几小的数
if(c>=k) //名次要更后
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
return ans;
}
int main()
{
int n, m, t, T, i, l, r, h;
scanf("%d", &T);
for(i=1; i<=T; ++i)
{
scanf("%d%d", &n, &m);
for(t=1; t<=n; ++t)
{
scanf("%d", sorted+t);
p[0][t]=sorted[t];
}
sort(sorted+1, sorted+n+1);
build(1, n, 0);
printf("Case %d:\n", i);
for(t=0; t<m; ++t)
{
scanf("%d%d%d", &l, &r, &h);
l++;
r++;
printf("%d\n", solve(l, r, h, n));
}
}
return 0;
}
hdu4417(划分树)--二分
最新推荐文章于 2019-04-06 17:53:05 发布
