设为首页 加入收藏

TOP

求区间内小于num的数的个数(三)
2012-11-17 09:26:51 来源: 作者: 【 】 浏览:1038
Tags:区间 小于 num 个数

 

    题意:

    输入cas

    n  m

    输入n个数

    输入m组 每组表示一个范围内l r 中小于num的数的个数

    注意从l是0开始的

    思路 :区间内找数  很容易联想到划分树  划分树是用来求一个区间内的第k大的数

    那么我们可以找出第1第2第3……大数的值 和num进行比较

    用二分法很容易找到第几大的数小于且等于num

    下面的几乎就是个模板       二分法居然也搞了我一下 坑爹

    [cpp]

    #include<stdio.h>

    #include<algorithm>

    using namespace std;

    #define M 100005

    int tree[40][M],sorted[M];

    int toLeft[40][M];

    void build(int level,int left,int right){

    if(left==right)return ;

    int mid=(left+right)》1;

    int i;

    int suppose;//假设在中位数sorted[mid]左边的数都全部小于sorted[mid]

    suppose=mid-left+1;

    for(i=left;i<=right;i++){

    if(tree[level][i]<sorted[mid]){

    suppose--;

    }

    }

    //如果suppose==1,则说明数组中值为sorted[mid]只有一个数。比如序列:1 3 4 5 6,sorted[mid]=4

    /*如果suppose>1,则说明数组中左半边值为sorted[mid]的不止一个数,为mid-suppose.比如序列:1 4 4 4 6,sorted[mid]=4

    */

    int lpos=left,rpos=mid+1;

    for(i=left;i<=right;i++){

    if(i==left)

    {//这里是预处理,相当与初始化

    toLeft[level][i]=0;

    }

    else

    {

    toLeft[level][i]=toLeft[level][i-1];

    }

    if(tree[level][i]<sorted[mid]){//划分到中位数左边

    toLeft[level][i]++;

    tree[level+1][lpos++]=tree[level][i];

    }else if(tree[level][i]>sorted[mid]){//划分到中位数右边

    tree[level+1][rpos++]=tree[level][i];

    }else{//这里,suppose大于0的数划分到中位数的左边

    if(suppose!=0){//这里的处理太巧妙了!帅气!

    suppose--;

    toLeft[level][i]++;

    tree[level+1][lpos++]=tree[level][i];

    }else{//表示

    tree[level+1][rpos++]=tree[level][i];

    }

    }

    }

    build(level+1,left,mid);

    build(level+1,mid+1,right);

    }

    //在[left,right]数据中查询[qleft,qright]中第k大的数据

    int query(int level,int left,int right,int qleft,int qright,int k){

    if( qleft==qright)

    return tree[level][qleft];

    int s;//代表[left,qleft)之间有多个个元素被分到左边

    int ss;//[qleft, qright]内将被划分到左子树的元素数目

    int mid=(left+right)》1;

    if(left==qleft){

    s=0;

    ss=toLeft[level][qright];

    }else{

    s=toLeft[level][qleft-1];

    ss=toLeft[level][qright]-s;

    }

    int newl,newr;

    if(k<=ss){//查询左边

    newl=left+s;

    newr=left+s+ss-1;

    return query(level+1,left,mid,newl,newr,k);

    }else{//查询右边

    newl=mid-left+1+qleft-s;

    newr=mid-left+1+qright-s-ss;

    return query(level+1,mid+1,right,newl, newr,k - ss);

    }

    }

    int main()

    {

    int n,m,cas,ca=0;

    scanf("%d",&cas);

    while(cas--)

    {

    printf("Case %d:\n",++ca);

    scanf("%d %d",&n,&m);

    int i;

    for(i=1;i<=n;i++){

    scanf("%d",&tree[0][i]);

    sorted[i]=tree[0][i];

    }

    sort(sorted+1,sorted+n+1);

    build(0,1,n);

    int ql,qr,num,ans=0;

    for(i=0;i<m;i++)

    {

    scanf("%d %d %d",&ql,&qr,&num);

    ql++;qr++;//注意这里哦  题意是按从0开始的

    int mid,left=1,right=qr-ql+1,ans=0;

    mid=(left+right)/2;

    while(left<=right)//别少了等于号

    {

    mid=(left+right)/2;

    if(query(0,1,n,ql,qr,mid)>num) right=mid-1;

    else  {ans=mid;left=mid+1;}//我一开始写的二分法居然不知道是哪里出错了一个劲RE

    }

    printf("%d\n",ans);

    }

    }       return 0;

    }

      

首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C++程序当中异常安全的思考 下一篇算法导论-二叉排序树

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: