HDOJ 4417 - Super Mario 划分树成熟模板(可解决相同元素)+二分

        题意:

                  给一列数..若干个询问..问(l,r,h)...在[l,r]范围内..有多少个数小于等于h....

        题解:

                  二分第k小..用划分树 查找第k小是哪个数..就可以把每个提问的答案找出来了...

                  读入数据后..忘记要L++,R++了..浪费了好多时间..终于把划分树的最终模板敲定了...去年网络赛的时候..看到这题.就想到了kth number..马上去找了个kth number的代码..加个二分.就水过了...当时运气也好..万一找打那份代码不能解决相同元素就要跪烂了...真正要自己来写前面的划分树.确实没这么轻松...

                  今天队内赛的一题和这道一模一样...改了一下提交..居然超时了..应该是spoj的机器太挫了吧...看来还是得用线段树(树状数组)来离线处理了..


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 100005
using namespace std; 
int tree[21][MAXN],num[21][MAXN],sorted[MAXN];
void built(int l,int r,int t)
{
       if (l==r) return;
       int i,x,y,mid=r+l>>1,m=mid-l+1;
       x=l,y=mid+1;
       for (i=l;i<=r;i++)
          if (sorted[i]<sorted[mid]) m--; 
       for (i=l;i<=r;i++)
       {
              num[t][i]=num[t][i-1];
              if (tree[t][i]==sorted[mid])
              {
                     if (m) tree[t+1][x++]=tree[t][i],num[t][i]++,m--;
                       else tree[t+1][y++]=tree[t][i];
              }else
              if (tree[t][i]<sorted[mid]) tree[t+1][x++]=tree[t][i],num[t][i]++;
                 else tree[t+1][y++]=tree[t][i];
       }
       built(l,mid,t+1),built(mid+1,r,t+1);
}
int query(int L,int R,int k,int l,int r,int t)
{
       if (L==R) return tree[t][L];
       int ltoL,LtoR,mid=l+r>>1;
       ltoL=num[t][L-1]-num[t][l-1],LtoR=num[t][R]-num[t][L-1];
       if (LtoR>=k) return query(l+ltoL,l+ltoL+LtoR-1,k,l,mid,t+1);
       int b=L-l-ltoL,bb=R-L+1-LtoR;  
       return query(mid+b+1,mid+b+bb,k-LtoR,mid+1,r,t+1);  
}
int main()
{           
       int T,cases,i,n,m;   
       scanf("%d",&T);
       for (cases=1;cases<=T;cases++)
       {
               scanf("%d%d",&n,&m);
               memset(num,0,sizeof(num));
               for (i=1;i<=n;i++) scanf("%d",&tree[0][i]),sorted[i]=tree[0][i];
               sort(sorted+1,sorted+1+n);
               built(1,n,0);
               printf("Case %d:\n",cases);
               while (m--)
               {
                       int L,R,H,l,r,mid;
                       scanf("%d%d%d",&L,&R,&H);
                       L++,R++;
                       l=0,r=R-L+2;
                       while (r-l>1)
                       {
                              mid=r+l>>1;
                              if (query(L,R,mid,1,n,0)<=H) l=mid;
                                  else r=mid;
                       }                    
                       printf("%d\n",l);  
               }
       }
       return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值