POJ-2761-Feed the dogs

这个题也是求区间k小数,用划分树做

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100100;
int n,m,sorted[maxn],tree[23][maxn],toleft[23][maxn];
void Build(int l,int r,int deep)
{
    if(l==r)
	return;
    int mid=(l+r)>>1;
    int same=mid-l+1;
    for(int i=l;i<=r;i++)
	if(tree[deep][i]<sorted[mid])
	    same--;
    int ls=l,rs=mid+1;
    for(int i=l;i<=r;i++)
    {
	toleft[deep][i]=toleft[deep][i-1];
	if(tree[deep][i]<sorted[mid])
	{
	    tree[deep+1][ls++]=tree[deep][i];
	    toleft[deep][i]++;
	}
	else if(tree[deep][i]==sorted[mid])
	{
	    if(same)
	    {
		tree[deep+1][ls++]=tree[deep][i];
		toleft[deep][i]++;
		same--;
	    }
	    else
		tree[deep+1][rs++]=tree[deep][i];
	}
	else
	    tree[deep+1][rs++]=tree[deep][i];
    }
    Build(l,mid,deep+1);
    Build(mid+1,r,deep+1);
}
int Query(int l,int r,int L,int R,int deep,int k)
{
    if(l==r)
	return tree[deep][l];
    int mid=(L+R)>>1;
    int x=toleft[deep][l-1]-toleft[deep][L-1];
    int y=toleft[deep][r]-toleft[deep][L-1];
    int ry=r-L-y;
    int rx=l-L-x;
    int cnt=y-x;
    if(cnt>=k)
	return Query(L+x,L+y-1,L,mid,deep+1,k);
    else
	return Query(mid+rx+1,mid+ry+1,mid+1,R,deep+1,k-cnt);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
	for(int i=1;i<=n;i++)
	{
	    scanf("%d",&sorted[i]);
	    tree[0][i]=sorted[i];
	}
	sort(sorted+1,sorted+1+n);
	Build(1,n,0);
	while(m--)
	{
	    int a,b,k;
	    scanf("%d%d%d",&a,&b,&k);
	    printf("%d\n",Query(a,b,1,n,0,k));
	}
    }
    return 0;
}


你可能感兴趣的:(划分树)