hdu 4417 Super Mario--二分--划分树

来源:互联网 发布:mac什么浏览器最好用 编辑:程序博客网 时间:2024/05/21 02:35
/*2012年杭州网络赛的题目就是求一个区间内<=某数  的个数我是用的二分划分树的方法做的*/#include<iostream>#include<algorithm>#include<stdio.h>using namespace std;const int N=100010;int srted[N];struct node{    int num[N];    int val[N];}t[40];int n,m;void build(int l,int r,int d)//建树  此树并非由节点构成 而是由数组的一段构成  如:d层的l~r是一个节点{    if(l==r) return;    int mid=(l+r)>>1;//取中间那个    int midd=srted[mid];    int same=mid-l+1,samed=0,zn=l-1,yn=mid,i;//same初识化为左孩子元素个数    //下面减去比midd小的(一定会进入左孩子里边)  剩下的就是==midd并且要进入左孩子的个数    //samed是已经插入的数目    //zn、yn是左右孩子的开始位置-1,下面会把元素分到两个孩子的区域里边    for(i=l;i<=r;++i)        if(t[d].val[i]<midd) --same;    for(i=l;i<=r;++i)//有点像快排  大的放到后边  小的放前边    相等的看情况    {        if(i==l) t[d].num[i]=0;        else t[d].num[i]=t[d].num[i-1];        if(t[d].val[i]<midd)        {            ++t[d].num[i];//这里是统计从l到i有多少元素进入了左孩子     这是划分树主要用到的数据            t[d+1].val[++zn]=t[d].val[i];        }else if(t[d].val[i]>midd)//进入右孩子        {            t[d+1].val[++yn]=t[d].val[i];        }else        {            if(samed<same)//名额还没有用完  放左孩子里边            {                ++samed;                ++t[d].num[i];                t[d+1].val[++zn]=t[d].val[i];            }else//方有孩子里边                t[d+1].val[++yn]=t[d].val[i];        }    }    build(l,mid,d+1);//建左右子树    build(mid+1,r,d+1);}int query(int a,int b,int k,int l,int r,int d)//在d层[l,r]的节点里查找[a,b]中的第k大值{    if(a==b) return t[d].val[a];    int mid=(l+r)>>1;    int sx=t[d].num[a-1],sy=t[d].num[b];    if(a-1<l) sx=0;    if(sy-sx>=k)//[a,b]进入左子树的元素>=k        return query(l+sx,l+sy-1,k,l,mid,d+1);    else    {        int s1=(a==1?0:a-l-sx);        int s2=(b-a+1)-(sy-sx);        int nk=k-(sy-sx);//前(sy-sx)大的元素在左子树里  剩下的在右子树里边找        return query(mid+1+s1,mid+s1+s2,nk,mid+1,r,d+1);    }}int solve(int n,int s,int t,int h){    int ans=0;    int l=1;    int r=(t-s)+1;    int mid;    while(l<=r)    {        mid=(l+r)>>1;        int temp=query(s,t,mid,1,n,0);        if(temp<=h)        {            ans=mid;            l=mid+1;        }        else r=mid-1;    }    return ans;}int main(){  //  freopen("in.txt","r",stdin);    int tt,ti,i;    int a,b,c,ret;    int min,max,mid;    scanf("%d",&tt);    for(ti=1;ti<=tt;ti++)    {        cout<<"Case "<<ti<<":\n";        scanf("%d%d",&n,&m);        for(i=1;i<=n;++i)        {            scanf("%d",&srted[i]);            t[0].val[i]=srted[i];        }        sort(srted+1,srted+1+n);        build(1,n,0);        for(i=1;i<=m;++i)        {            scanf("%d%d%d",&a,&b,&c);            a++,b++;            if(a==b)            {                if(t[0].val[a]<=c)                    cout<<"1"<<endl;                else cout<<"0"<<endl;                continue;            }            cout<<solve(n,a,b,c)<<endl;        }    }    return 0;}

原创粉丝点击