CODEFORCES 484E Sign on Fence

链接

http://codeforces.com/contest/484/problem/E

题意

给出 n 个宽度为 1 ,高度为 h[i] 的矩形,从 1 到 n 连续挨着排。有 m 次询问,每次询问一段区间 [l, r] 中组成宽度为 w 的矩形的最高高度是多少?(n, m ≤ 1e5, h[i] ≤ 1e9)

思路

自己没想到。听子卿讲题解。

二分答案

二分答案 h,判定 [l, r] 内不低于 h 的矩形是否有连续 w 个。

对于固定 h 的判定问题,我们只要建立一颗线段树,区间存内部大于等于 h 的最长区间长度,靠左靠右的最长区间长度还有本区间长度,进行区间合并。查询 [l, r] 最长连续长度,如果大于等于 w 那么判断就通过。

可持久化

有了上述分析,这个问题要解决的话,只要把对应每个高度的线段树都建立出来就可以了。但是一颗一颗建立显然是不允许的。

注意到线段树之间有共用关系,比如数据是:1 2 2 3。如果对应高度 3 建立了线段树,那么高度为 2 对应的线段树可以看做是高度 3 的线段树进行单点更新(两次)的结果。

如此一来,我们可以将线段树可持久化,解决线段树的建立问题。

复杂度容易知道是:629657-20160519100525732-1647884867.png,可以通过该题。

错误

我昨晚写这个题的时候犯了个错误,导致一直没过。

错误主要原因是建树出错,从前建树为了节省时间和内存,函数式的起始树我不会完整的建立,而是用一个点代替,所有要访问这个起始树的都访问到这一个节点。一般这个节点的标号是 0,左右儿子的标号也是 0。起始树当然标记成 root[0] = 0。

但是没有深刻的认识到这个技巧只能用于空树的所有节点的值都相同的状况。对于这个题目,因为我对每个点存了本区间长度,所以是不能这样用的。

代码

  1. // c head files 
  2. #include <stdio.h> 
  3. #include <assert.h> 
  4. // c++ head files 
  5. #include <algorithm> 
  6. using std::max; 
  7. using std::sort; 
  8. using std::unique; 
  9. #include <iostream> 
  10. using std::cout
  11. using std::endl; 
  12.  
  13. const int MAXN = 100000 + 5
  14. const int LOG = 20
  15. const int MAXT = LOG * MAXN; 
  16.  
  17. namespace FST 

  18. struct TNode 

  19. int len; 
  20. int lenL; 
  21. int lenR; 
  22. int lenMax; 
  23.  
  24. int lson; 
  25. int rson; 
  26. } tree[MAXT]; 
  27.  
  28. int nodeCnt = 0
  29.  
  30. typedef TNode& ref; 
  31. typedef const ref cref; 
  32.  
  33. void push(cref l, cref r, ref now) 

  34. now.len = l.len + r.len; 
  35. now.lenMax = max(max(l.lenMax, r.lenMax), l.lenR + r.lenL); 
  36. now.lenL = l.lenL + (l.lenL == l.len ? r.lenL : 0); 
  37. now.lenR = r.lenR + (r.lenR == r.len ? l.lenR : 0); 

  38.  
  39. void push(ref now) 

  40. int l = now.lson; 
  41. int r = now.rson; 
  42. push(tree[l], tree[r], now); 

  43.  
  44. void init(int& now, int l, int r) 

  45. now = nodeCnt++; 
  46. if (l == r) { 
  47. tree[now].len = 1
  48. tree[now].lenL = 0
  49. tree[now].lenR = 0
  50. tree[now].lenMax = 0
  51. return

  52. int mid = (l + r) >> 1
  53. init(tree[now].lson, l, mid); 
  54. init(tree[now].rson, mid + 1, r); 
  55. push(tree[now]); 

  56.  
  57. void init(int n, int& root0) 

  58. nodeCnt = 0
  59. init(root0, 1, n); 

  60.  
  61. void update(int& now, int l, int r, int i) 

  62. tree[nodeCnt] = tree[now]; 
  63. now = nodeCnt++; 
  64. assert(nodeCnt < MAXT); 
  65. if (l == r) { 
  66. tree[now].len = 1
  67. tree[now].lenL = 1
  68. tree[now].lenR = 1
  69. tree[now].lenMax = 1
  70. return

  71. int mid = (l + r) >> 1
  72. if (i <= mid) 
  73. update(tree[now].lson, l, mid, i); 
  74. else update(tree[now].rson, mid + 1, r, i); 
  75. push(tree[now]); 
  76. assert(tree[now].len == (r - l + 1)); 

  77.  
  78. TNode query(int now, int l, int r, int ql, int qr) 

  79. if (ql == l && qr == r) 
  80. return tree[now]; 
  81. int mid = (l + r) >> 1
  82. if (qr <= mid) 
  83. return query(tree[now].lson, l, mid, ql, qr); 
  84. if (ql > mid) 
  85. return query(tree[now].rson, mid + 1, r, ql, qr); 
  86.  
  87. TNode lson, rson, result; 
  88. lson = query(tree[now].lson, l, mid, ql, mid); 
  89. rson = query(tree[now].rson, mid + 1, r, mid + 1, qr); 
  90. push(lson, rson, result); 
  91. return result; 

  92.  
  93. int query(int now, int n, int ql, int qr) 

  94. return query(now, 1, n, ql, qr).lenMax; 


  95.  
  96. using FST::query; 
  97. using FST::update; 
  98. using FST::init; 
  99.  
  100. struct Node 

  101. int value; 
  102. int index; 
  103. } a[MAXN]; 
  104.  
  105. int value[MAXN]; 
  106. int root[MAXN]; 
  107.  
  108. bool cmp(const Node& a, const Node& b) 

  109. return a.value < b.value; 

  110.  
  111. int main() 

  112. #ifndef ONLINE_JUDGE 
  113. freopen("data.in", "r", stdin); 
  114. #endif // ONLINE_JUDGE 
  115. int n; 
  116. int cnt; 
  117. scanf("%d", &n); 
  118. for (int i = 1; i <= n; i++) { 
  119. scanf("%d", &a[i].value); 
  120. a[i].index = i; 
  121. value[i] = a[i].value; 

  122. sort(a + 1, a + n + 1, cmp); 
  123. sort(value + 1, value + n + 1); 
  124. cnt = unique(value + 1, value + n + 1) - (value + 1); 
  125. init(n, root[0]); 
  126. for (int i = cnt, j = n; i >= 1; i--) { 
  127. root[i] = root[(i + 1) % (cnt + 1)]; 
  128. for (; j >= 1 && a[j].value == value[i]; j--) 
  129. update(root[i], 1, n, a[j].index); 

  130.  
  131. int m; 
  132. int l, r, w; 
  133. int low, upp, mid; 
  134. scanf("%d", &m); 
  135. for (; m--; ) { 
  136. scanf("%d %d %d", &l, &r, &w); 
  137. low = 0
  138. upp = cnt + 1
  139. // [low, upp) 
  140. for (; upp - low > 1; ) { 
  141. mid = (low + upp) >> 1
  142. if (query(root[mid], n, l, r) >= w) 
  143. low = mid; 
  144. else upp = mid; 

  145. printf("%d\n", value[low]); 

  146. return 0

转载于:https://www.cnblogs.com/gu-castle/p/5507707.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值