zoukankan      html  css  js  c++  java
  • 区间第k小值logn方法划分树模板HDOJ 4417 Super Mario

    http://acm.hdu.edu.cn/showproblem.php?pid=4417

    ------ 划分树 + 二分 

    划分树模板求区间第k小数,那么我们每次询问时就二分查找当前H算第几小数,那么显然答案就出来了~需要注意的就是区间全包括和全不包括需要特判一下,不然会RE。。。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cmath>
      5 #include <vector>
      6 #include <stack>
      7 #include <queue>
      8 #include <map>
      9 #include <algorithm>
     10 #include <string>
     11 #include <cstring>
     12 #define MID(x,y) ((x+y)>>1)
     13 
     14 using namespace std;
     15 #define M 100010
     16 struct Seg_Tree
     17 {
     18     int left,right;
     19     int mid()
     20     {
     21         return (left + right) >> 1;
     22     }
     23 }tt[M<<2];
     24 int len;
     25 int sorted[M];
     26 int toLeft[40][M];
     27 int val[40][M];
     28 
     29 void build(int l,int r,int d,int idx)
     30 {
     31     tt[idx].left = l;
     32     tt[idx].right = r;
     33     if(tt[idx].left == tt[idx].right)    return ;
     34     int mid = tt[idx].mid();
     35     int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的
     36     for(int i = l ; i <= r ; i ++)
     37     {
     38         if(val[d][i] < sorted[mid])
     39         {
     40             lsame --;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去
     41         }
     42     }
     43     int lpos = l;
     44     int rpos = mid + 1;
     45     int same = 0;
     46     for(int i = l ; i <= r ; i ++)
     47     {
     48         if(i == l)
     49         {
     50             toLeft[d][i] = 0;//toLeft[i]表示[ tt[idx].left , i ]区域里有多少个数分到左边
     51         }
     52         else
     53         {
     54             toLeft[d][i] = toLeft[d][i-1];
     55         }
     56         if(val[d][i] < sorted[mid])
     57         {
     58             toLeft[d][i] ++;
     59             val[d+1][lpos++] = val[d][i];
     60         }
     61         else if(val[d][i] > sorted[mid])
     62         {
     63             val[d+1][rpos++] = val[d][i];
     64         }
     65         else
     66         {
     67             if(same < lsame)
     68             {//有lsame的数是分到左边的
     69                 same ++;
     70                 toLeft[d][i] ++;
     71                 val[d+1][lpos++] = val[d][i];
     72             }
     73             else
     74             {
     75                 val[d+1][rpos++] = val[d][i];
     76             }
     77         }
     78     }
     79     build(l,mid,d+1,idx<<1);
     80     build(mid+1,r,d+1,idx<<1|1);
     81 }
     82 
     83 int query(int l,int r,int k,int d,int idx) {
     84     if(l == r)
     85     {
     86         return val[d][l];
     87     }
     88     int s;//s表示[ l , r ]有多少个分到左边
     89     int ss;//ss表示 [tt[idx].left , l-1 ]有多少个分到左边
     90     if(l == tt[idx].left)
     91     {
     92         s = toLeft[d][r];
     93         ss = 0;
     94     }
     95     else
     96     {
     97         s = toLeft[d][r] - toLeft[d][l-1];
     98         ss = toLeft[d][l-1];
     99     }
    100     if(s >= k)
    101     {//有多于k个分到左边,显然去左儿子区间找第k个
    102         int newl = tt[idx].left + ss;
    103         int newr = tt[idx].left + ss + s - 1;//计算出新的映射区间
    104         return query(newl,newr,k,d+1,idx<<1);
    105     }
    106     else
    107     {
    108         int mid = tt[idx].mid();
    109         int bb = l - tt[idx].left - ss;//bb表示 [tt[idx].left , l-1 ]有多少个分到右边
    110         int b = r - l + 1 - s;//b表示 [l , r]有多少个分到右边
    111         int newl = mid + bb + 1;
    112         int newr = mid + bb + b;
    113         return query(newl,newr,k-s,d+1,idx<<1|1);
    114     }
    115 }
    116 
    117 int BS(int r, int h, int L, int R)
    118 {
    119     int l = 0;
    120     while(l < r)
    121     {
    122         int mid = MID(l,r);
    123         if (query(L,R,mid,0,1) > h)
    124             r = mid;
    125         else    l = mid + 1;
    126     }
    127     return l;
    128 }
    129 
    130 int main()
    131 {
    132     //freopen("test.in","r+",stdin);
    133 
    134     int t,caseo = 1;
    135     scanf("%d", &t);
    136     while(t--)
    137     {
    138         printf("Case %d:\n",caseo ++);
    139         int n,m;
    140         scanf("%d%d",&n, &m);
    141         for (int i = 1;i <= n; i++)
    142         {
    143             scanf("%d", &val[0][i]);
    144             sorted[i] = val[0][i];
    145         }
    146         sort(sorted+1,sorted+n+1);
    147         build(1,n,0,1);
    148         for (int i = 0; i < m; i++)
    149         {
    150             int L,R,H;
    151             scanf("%d%d%d",&L, &R, &H);
    152             if (query(L+1,R+1,1,0,1) > H )
    153                 puts("0");
    154             else if (query(L+1,R+1,R-L+1,0,1) <= H)
    155                 printf("%d\n",R-L+1);
    156             else
    157             {
    158                 int res = BS(R-L+1,H,L+1,R+1);
    159                 while(res != 0 && query(L+1,R+1,res,0,1) > H)
    160                     res--;
    161                 printf("%d\n",res);
    162 
    163             }
    164         }
    165     }
    166     return 0;
    167 }
    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    Linux查看磁盘空间大小
    Qt常见错误
    顺序查找和二分查找代码
    字典树——动态&&静态
    Linux本机和远程服务器之间文件的上传和下载 rz sz
    牛顿迭代法——C语言
    MFC之ListControl选中行删除
    MFC之登录框的问题处理
    MFC之创建多级动态菜单
    c++动态内存知识总结与疑问
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/2699131.html
Copyright © 2011-2022 走看看