会议中心

离散化贪心不多说了。然后在字典序最小上卡思路……想到了这个题要维护字典序最小的话,就应该按照顺序判断某线段可行与否。该线段[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.  

发布了0 篇原创文章 · 获赞 1 · 访问量 884
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览