Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 43988 | Accepted: 14569 | |
Case Time Limit: 2000MS |
Description
Input
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
Source
有没有觉得题目很熟悉啊?是不是感觉和poj2761很像啊?不过这道题稍微麻烦一点,区间之间存在包含关系,所以就不能用排序+平衡树做了。
这道题的正确解法是划分树(可用于求区间第k小数,复杂度log(n))。划分树是一种基于线段树的数据结构,基本思想是对于一个区间,将它划分成两个区间,左区间的数全部小于等于右区间的数,分别对应左右子树。构建划分树时要记录到达某个位置时进入左子树的数的个数num,查询时就可以通过num确定下一个查询区间,最后将区间范围缩小到1,也就找到了答案。(详见代码…)
#include
#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define pa pair
#define MAXN 100005
using namespace std;
int n,m,a[MAXN],val[20][MAXN],num[20][MAXN];
inline int read()
{
int ret=0,flag=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') flag=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
return ret*flag;
}
inline void build(int l,int r,int x)
{
if (l==r) return;
int mid=(l+r)>>1,lsame=mid-l+1,same=0,ln=l,rn=mid+1;
F(i,l,r) if (val[x][i]a[mid]) val[x+1][rn++]=val[x][i];
else
{
if (lsame>=++same) num[x][i]++,val[x+1][ln++]=val[x][i];
else val[x+1][rn++]=val[x][i];
}
}
build(l,mid,x+1);
build(mid+1,r,x+1);
}
inline int query(int st,int ed,int k,int l,int r,int x)
{
if (l==r) return val[x][l];
int lx,ly,rx,ry,mid=(l+r)>>1;
if (st==l) lx=0,ly=num[x][ed];
else lx=num[x][st-1],ly=num[x][ed]-lx;
if (ly>=k)
{
st=l+lx;ed=st+ly-1;
return query(st,ed,k,l,mid,x+1);
}
else
{
rx=st-l-lx;ry=ed-st+1-ly;
st=mid+1+rx;ed=st+ry-1;
return query(st,ed,k-ly,mid+1,r,x+1);
}
}
int main()
{
n=read();m=read();
F(i,1,n) val[0][i]=a[i]=read();
sort(a+1,a+n+1);
build(1,n,0);
F(i,1,m)
{
int x=read(),y=read(),k=read();
printf("%d\n",query(x,y,k,1,n,0));
}
}