会议中心

离散化贪心不多说了。然后在字典序最小上卡思路……想到了这个题要维护字典序最小的话,就应该按照顺序判断某线段可行与否。该线段[L, R]可行要满足以下两个条件:

1) 这条线段没有接触到任何一个被覆盖的点。

2) 那么这条线段一定落在一个可行区间[L', R']中。设MT(A, B)表示区间[A, B]最多能放几条线段,就必须满足MT(L', L - 1) + MT(R + 1, R') + 1 = MT(L', R')。

如果这条线段可行,那么就输出它,并且把这条线段所在的区间分断成[L', L - 1]和[R + 1, R']。

这个解决方案有这样几个问题没有解决:

首先,查找[L, R]所在区间。这个不多说,直接用平衡树。当然线段树也是可以的。

之后就是MT函数的计算。这可是这个题的精髓所在!

首先我们去掉所有包含其他线段的线段,并按照其L排序。显然这时R也是排好序的。

设RIGHT(x)为从x开始向右走,遇到的第一个区间的右边界加一(若是x右边一个可行区间都没有就返回infinite)。设M(0, x) = RIGHT(x),M(k, x) = RIGHT(M(k - 1, x))。那么,MT(L, R) = max { k | M(K, L) <= R + 1 }。对于这种问题,有一个大杀器可用,那就是倍增。我们首先要预处理一个二维数组jump,使得jump[k][x] = M(2^k, x),预处理这个数组可以用jump[0][x] = RIGHT(x),jump[k][x] = jump[k - 1][jump[k - 1][x]]来做。之后,求MT(L, R)的方法就变得简单啦:首先从高到底枚举i,0->ans,如果jump[i][L] <= R + 1,那么ans + 1<<i -> ans,jump[i][L] -> L,一直做下去直到i = 0计算完毕。这样的复杂度是O(logN)。

总体时间复杂度就是O(NlogN)。


  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>
  4. #include <vector>
  5. #include <set>
  6. #include <algorithm>
  7. using namespace std ;
  8.  
  9. const int mi = 19931117 ;
  10. int lsh [ 500020 ], lsht [ 500020 ], lshmr ;
  11. void initialize ( void )
  12. {
  13. sort (lsh, lsh + lshmr ) ;
  14. int cnt = 0 ;
  15. for ( int i = 0 ; i < lshmr ; i ++ )
  16. {
  17. if (i == 0 || lsh [i ] ! = lsh [i - 1 ] )
  18. lsht [cnt ++ ] = lsh [i ] ;
  19. } lshmr = cnt ;
  20. }
  21. inline int place ( int a )
  22. {
  23. int st = 0, ed = lshmr, mid ;
  24. while (ed - st > 1 )
  25. {
  26. mid = (st + ed ) >> 1 ;
  27. if (lsht [mid ] > a ) ed = mid ;
  28. else st = mid ;
  29. } return st + 1 ;
  30. }
  31. pair < int, int > require [ 250010 ] ;
  32. pair < int, int > rs [ 250010 ], trs [ 250010 ] ; int trmr ;
  33. bool comp ( const pair < int, int > & a, const pair < int, int > & b )
  34. {
  35. if (a. first ! = b. first ) return a. first < b. first ;
  36. else return a. second > b. second ;
  37. }
  38.  
  39. int jump [ 20 ] [ 500010 ], maxj ;
  40. void jump_st ( void )
  41. {
  42. int p = 0 ; jump [ 0 ] [lshmr + 1 ] = mi ;
  43. for ( int i = lshmr ; i >= 1 ; i -- )
  44. {
  45. if (p < trmr && i == trs [p ]. first ) jump [ 0 ] [i ] = trs [p ++ ]. second + 1 ;
  46. else jump [ 0 ] [i ] = jump [ 0 ] [i + 1 ] ;
  47. }
  48. bool valid ;
  49. for ( int i = 1 ; ; i ++ )
  50. {
  51. valid = false ;
  52. jump [i ] [lshmr + 1 ] = mi ;
  53. for ( int k = 1 ; k <= lshmr ; k ++ )
  54. {
  55. if (jump [i - 1 ] [k ] == mi ) jump [i ] [k ] = mi ;
  56. else jump [i ] [k ] = jump [i - 1 ] [jump [i - 1 ] [k ] ] ;
  57. if (jump [i ] [k ] < mi ) valid = true ;
  58. }
  59. if (valid == false ) { maxj = i - 1 ; break ; }
  60. }
  61. }
  62. int max_time ( int s, int e )
  63. {
  64. if (s >= e ) return 0 ;
  65. int ts = s, ans = 0 ; ++e ;
  66. for ( int j = maxj ; j >= 0 && ts < e ; j -- )
  67. if (jump [j ] [ts ] <= e ) ts = jump [j ] [ts ], ans + = ( 1 << j ) ;
  68. return ans ;
  69. }
  70. set <pair < int, int > > query ;
  71. typedef set <pair < int, int > > :: iterator ptr ; int ans ;
  72. bool judge ( int i )
  73. {
  74. int l = require [i ]. first, r = require [i ]. second ;
  75. ptr t1, t2 ;
  76. t1 = query. lower_bound (make_pair (l, mi ) ) ;
  77. if (t1 == query. begin ( ) ) return false ; else --t1 ;
  78. if (t1 - >second < l ) return false ;
  79. t2 = --query. lower_bound (make_pair (r, mi ) ) ;
  80. if (t1 ! = t2 ) return false ;
  81. if (t1 - >second < r ) return false ;
  82. int ll = t1 - >first, rr = t1 - >second ;
  83. int tans = max_time (ll, l - 1 ) + max_time (r + 1, rr ) + 1 ;
  84. int sans = max_time (ll, rr ) ;
  85. if (tans < sans ) return false ;
  86. else
  87. {
  88. query. erase (t1 ) ;
  89. if (ll <= l - 1 ) query. insert (make_pair (ll, l - 1 ) ) ;
  90. if (r + 1 <= rr ) query. insert (make_pair (r + 1, rr ) ) ;
  91. return true ;
  92. }
  93. }
  94. int main ( )
  95. {
  96. int n, ans ; scanf ( "%d", &n ), lshmr = 0 ;
  97. for ( int i = 0 ; i < n ; i ++ )
  98. {
  99. scanf ( "%d %d", &require [i ]. first, &require [i ]. second ) ;
  100. lsh [lshmr ++ ] = require [i ]. first ;
  101. lsh [lshmr ++ ] = require [i ]. second ;
  102. }
  103. initialize ( ) ;
  104. for ( int i = 0 ; i < n ; i ++ )
  105. {
  106. int l = place (require [i ]. first ), r = place (require [i ]. second ) ;
  107. require [i ]. first = l, require [i ]. second = r ;
  108. rs [i ] = make_pair (l, r ) ;
  109. }
  110. sort (rs, rs + n, comp ), trmr = 0 ; int p ;
  111. for ( int i = n - 1 ; i >= 0 ; i -- )
  112. {
  113. if (i == n - 1 || rs [i ]. second < rs [p ]. second )
  114. trs [trmr ++ ] = rs [i ], p = i ;
  115. }
  116. jump_st ( ) ;
  117. query. insert (make_pair ( 1, lshmr ) ) ;
  118. printf ( "%d\n", ans = max_time ( 1, lshmr ) ) ;
  119. for ( int i = 0 ; i < n ; i ++ )
  120. if (judge (i ) ) printf ( "%d ", i + 1 ) ;
  121. printf ( "\n" ) ;
  122. return 0 ;
  123. }
  124.  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值