hdu 4417(划分树+二分)

来源:互联网 发布:linux top 指定进程 编辑:程序博客网 时间:2024/05/18 06:41

求一个静态区间里,小于等于H的数有多少个。

二分第k小,用划分树找到第一个大于H的数,它是第K小,那么就有K-1个数小于H。

代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAX 101000#define MID(a,b) (a+((b-a)>>1))int n,m;int sorted[MAX];struct ptree{    int val[MAX];    int num[MAX];};ptree tree[20];void build_tree(int l,int r,int p){    int i,j;    if(l==r) return ;    int mid=MID(l,r);    int lsame=mid-l+1,same=0,ln=l,rn=mid+1;    for(i=l;i<=r;i++) if(tree[p].val[i]<sorted[mid]) lsame--;    for(i=l;i<=r;i++)    {        if(i==l) tree[p].num[i]=0;        else tree[p].num[i]=tree[p].num[i-1];        if(tree[p].val[i]<sorted[mid])        {            tree[p].num[i]++;            tree[p+1].val[ln++]=tree[p].val[i];        }        else if(tree[p].val[i]>sorted[mid])        {            tree[p+1].val[rn++]=tree[p].val[i];        }        else        {            same++;            if(lsame>=same)            {                tree[p].num[i]++;                tree[p+1].val[ln++]=tree[p].val[i];            }            else            {                tree[p+1].val[rn++]=tree[p].val[i];            }        }    }    build_tree(l,mid,p+1);    build_tree(mid+1,r,p+1);}int query(int l,int r,int left,int right,int k,int p){    if(left==right) return tree[p].val[left];    int mid=MID(left,right);    int lx,ly,rx,ry;    /*        lx表示从lft到st-1这段区间内有多少个数进入左子树        ly表示从st到ed这段区间内有多少个数进入左子树        rx表示从lft到st-1这段区间内有多少个数进入右子树        ry表示从st到ed这段区间内有多少个数进入右子树     */    if(l==left)    {        lx=0;ly=tree[p].num[r];    }    else{        lx=tree[p].num[l-1];ly=tree[p].num[r]-lx;    }    if(k<=ly)    {        l=left+lx;        r=left+lx+ly-1;        return query(l,r,left,mid,k,p+1);    }    else    {        rx=l-left-lx;        ry=r-l+1-ly;        l=mid+rx+1;        r=mid+rx+ry;        return query(l,r,mid+1,right,k-ly,p+1);    }}int main(){    int i,j,k;    int L,R,H;    int T,casei=0;    int num;    scanf("%d",&T);    while(T--)    {        casei++;        scanf("%d%d",&n,&m);        for(i=1;i<=n;i++)        {scanf("%d",&tree[0].val[i]);sorted[i]=tree[0].val[i];}        sort(sorted+1,sorted+n+1);        build_tree(1,n,0);        printf("Case %d:\n",casei);        for(i=1;i<=m;i++)        {            scanf("%d%d%d",&L,&R,&H);            L++;R++;            num=R-L+1;            if(query(L,R,1,n,num,0)<=H) {printf("%d\n",num);continue;}            if(query(L,R,1,n,1,0)>H) {printf("0\n");continue;}            int Min=1,Max=num,mid,pos;            while(Min<Max)            {                mid=(Min+Max)>>1;                int temp=query(L,R,1,n,mid,0);                if(temp<=H) {Min=mid+1;pos=Min;}                else {Max=mid;pos=Max;}            }            printf("%d\n",pos-1);        }    }    return 0;}

 

0 0
原创粉丝点击