hdu4417:super mario

 

 
 
  1. #include <iostream> 
  2. #include<algorithm> 
  3. #include<cstdio> 
  4. using namespace std; 
  5. #define M 100005 
  6. int tree[40][M]; 
  7. int toLeft[40][M]; 
  8. int sorted[M]; 
  9. int n,m; 
  10. void build(int level,int ll,int rr){ 
  11.     if(ll==rr)return
  12.     int mid=(ll+rr)>>1; 
  13.     int i,suppose; 
  14.     suppose=mid-ll+1; 
  15.     for(i=ll;i<=rr;i++){ 
  16.         if(tree[level][i]<sorted[mid]){ 
  17.             suppose--; 
  18.         } 
  19.     } 
  20.  
  21.     int lpos=ll,rpos=mid+1; 
  22.     for(i=ll;i<=rr;i++){ 
  23.         if(i==ll){ 
  24.             toLeft[level][i]=0; 
  25.         }else
  26.             toLeft[level][i]=toLeft[level][i-1]; 
  27.         } 
  28.         if(tree[level][i]<sorted[mid]){ 
  29.             toLeft[level][i]++; 
  30.             tree[level+1][lpos++]=tree[level][i]; 
  31.         }else if(tree[level][i]>sorted[mid]){ 
  32.             tree[level+1][rpos++]=tree[level][i]; 
  33.         }else
  34.             if(suppose!=0){ 
  35.                 suppose--; 
  36.                 toLeft[level][i]++; 
  37.                 tree[level+1][lpos++]=tree[level][i]; 
  38.             }else
  39.                 tree[level+1][rpos++]=tree[level][i]; 
  40.             } 
  41.         } 
  42.     } 
  43.     build(level+1,ll,mid); 
  44.     build(level+1,mid+1,rr); 
  45. //在[left,right]数据中查询[qleft,qright]中第k大的数据 
  46. int query(int level,int left,int right,int qleft,int qright,int k){ 
  47.     if( qleft==qright) 
  48.         return tree[level][qleft]; 
  49.     int s;//代表[left,qleft)之间有多个个元素被分到左边 
  50.     int ss;//[qleft, qright]内将被划分到左子树的元素数目 
  51.     int mid=(left+right)>>1; 
  52.     if(left==qleft){ 
  53.         s=0; 
  54.         ss=toLeft[level][qright]; 
  55.     }else
  56.         s=toLeft[level][qleft-1]; 
  57.         ss=toLeft[level][qright]-s; 
  58.     } 
  59.     int newl,newr; 
  60.     if(k<=ss){//查询左边 
  61.         newl=left+s; 
  62.         newr=left+s+ss-1; 
  63.         return query(level+1,left,mid,newl,newr,k); 
  64.     }else{//查询右边 
  65.         newl=mid-left+1+qleft-s; 
  66.         newr=mid-left+1+qright-s-ss; 
  67.         return query(level+1,mid+1,right,newl, newr,k - ss); 
  68.     } 
  69. int solve(int ll,int rr,int h){ 
  70.     int l=1,r=(rr-ll)+1; 
  71.     int mid; 
  72.     int ans=0; 
  73.     while(l<=r){ 
  74.         mid=(l+r)>>1; 
  75.         int tmp=query(0,1,n,ll,rr,mid); 
  76.         if(tmp<=h){ 
  77.             ans=mid; 
  78.             l=mid+1; 
  79.         }else
  80.             r=mid-1; 
  81.         } 
  82.     } 
  83.     return ans; 
  84. int main(){ 
  85.     int t,ti=1; 
  86.     int i; 
  87.     scanf("%d",&t); 
  88.     while(t--){ 
  89.         scanf("%d %d",&n,&m); 
  90.         for(i=1;i<=n;i++){ 
  91.             scanf("%d",&tree[0][i]); 
  92.             sorted[i]=tree[0][i]; 
  93.         } 
  94.         sort(sorted+1,sorted+n+1); 
  95.         build(0,1,n); 
  96.         printf("Case %d:\n",ti++); 
  97.         int ll,rr,h; 
  98.         for(i=0;i<m;i++){ 
  99.             scanf("%d %d %d",&ll,&rr,&h); 
  100.             ll++,rr++; 
  101.             if(ll==rr){ 
  102.                 if(tree[0][ll]<=h){ 
  103.                     printf("1\n"); 
  104.                 }else
  105.                     printf("0\n"); 
  106.                 } 
  107.             }else
  108.                 printf("%d\n",solve(ll,rr,h)); 
  109.             } 
  110.  
  111.         } 
  112.     } 
  113. return 0; 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值