Pku2104 k - th number

解题方法:线段树 + 归并排序 + 二分枚举

本人比较笨,这道题看了N天,主要花在二分枚举上,虽然AC,至今仍然还不是很清楚二分枚举的原理。

希望牛人路过,指导下。

  1. #include <stdio.h>
  2. #include <memory.h>
  3. const long MAX = 100001 ;
  4. inline int tMin( int u , int v )
  5. {
  6.     return ( u > v ? v : u ) ;
  7. }
  8. inline int tMax( int u , int v )
  9. {
  10.     return ( u > v ? u : v ) ;
  11. }
  12. struct STREE
  13. {
  14.     int start ;
  15.     int end ;
  16.     int level ;
  17.     struct STREE *leftc ;
  18.     struct STREE *rightc ;
  19.     void BuildST( int s , int e , int lv ) ;
  20.     int Query( int s , int e , int val ) ;
  21. }Stree[(MAX << 1) + 100] ;
  22. STREE *root = &Stree[0] ;
  23. int pos = 1 ;
  24. int sortarr[18][MAX] ;
  25. int gNum[MAX] ;
  26. void STREE::BuildST( int s, int e, int lv )
  27. {
  28.     start = s ;
  29.     end = e ;
  30.     level = lv ;
  31.     if ( s == e )
  32.     {
  33.         leftc = rightc = NULL ;
  34.         sortarr[lv][s] = gNum[s] ;
  35.         return ;
  36.     }
  37.     
  38.     int mid = ( s + e ) >> 1 ;
  39.     leftc = &Stree[pos++] ;
  40.     rightc = &Stree[pos++] ;
  41.     leftc->BuildST( s , mid , lv + 1 ) ;
  42.     rightc->BuildST( mid + 1 , e , lv + 1 ) ;
  43.     int i = s , j = mid + 1 , k = s ;
  44.     
  45.     while ( i <= mid && j <= e )
  46.     {
  47.         if ( sortarr[lv + 1][i] < sortarr[lv + 1][j] )
  48.             sortarr[lv][k++] = sortarr[lv + 1][i++] ;
  49.         else {
  50.             sortarr[lv][k++] = sortarr[lv + 1][j++] ;
  51.         }
  52.     }
  53.     while ( i <= mid )
  54.     {
  55.         sortarr[lv][k++] = sortarr[lv + 1][i++] ;
  56.     }
  57.     while ( j <= e )
  58.     {
  59.         sortarr[lv][k++] = sortarr[lv + 1][j++] ;
  60.     }
  61. }
  62. int STREE::Query( int s, int e, int val )
  63. {
  64.     int ret , mid , l = s , r = e ;
  65.     if ( s == start && end == e )
  66.     {
  67.         if ( val <= sortarr[level][start] ) return 0 ;
  68.         if ( val > sortarr[level][end] ) return ( end - start + 1 ) ;
  69.         if ( val == sortarr[level][end] ) return ( end - start ) ;
  70.         while ( l <= r )
  71.         {
  72.             mid = l + (( r - l ) >> 1) ;
  73.             if ( val <= sortarr[level][mid] )
  74.                 r = mid - 1 ;
  75.             else l = mid + 1 ;
  76.         }
  77.         return l - start ;
  78.     }
  79.     else {
  80.         ret = 0 ;
  81.         mid = start + (( end - start ) >> 1) ;
  82.         if ( mid >= s ) ret += leftc->Query( s, tMin(e,mid), val) ;
  83.         if ( mid + 1 <= e ) ret += rightc->Query( tMax(s,mid+1), e, val) ;
  84.         return ret ;
  85.     }
  86. }
  87. int main()
  88. {
  89.     int n , m , s , e , k , i , l , r , mid ;
  90.     scanf("%d %d", &n, &m) ;
  91.     for ( i = 1 ; i <= n ; i++ )
  92.     {
  93.         scanf("%ld", &gNum[i]);
  94.     }
  95.     root->BuildST( 1 , n , 0 ) ;
  96.     for ( i = 1 ; i <= m ; i++ )
  97.     {
  98.         scanf("%d %d %d", &s, &e, &k) ;
  99.         l = 1 , r = n ;
  100.         while ( l <= r )
  101.         {
  102.             mid = l + ((r - l) >> 1) ;
  103.             int p = root->Query( s, e, sortarr[0][mid] ) ;
  104.             if ( k > p )
  105.                 l = mid + 1 ;
  106.             else r = mid - 1 ;
  107.         }
  108.         printf("%d/n", sortarr[0][r] ) ;
  109.     }
  110.     return 0 ;
  111. }

参考某牛人的代码:http://www.wiskey86.cn/wordpress/?p=24

在此感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值