hdu 4417 划分树+二分

来源:互联网 发布:怎么在电脑上清理数据 编辑:程序博客网 时间:2024/05/22 06:33
/*划分树+二分,二分第k个数题意:给一列数..若干个询问..问(l,r,h)...在[l,r]范围内..有多少个数小于等于h*/#include<stdio.h>#include<algorithm>#include<string.h>#define N 100100using 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;}

0 0
原创粉丝点击