[关闭]
@ZCDHJ 2018-09-29T14:05:42.000000Z 字数 1231 阅读 557

BZOJ2957 楼房重建

线段树


Lydsy

如果 的楼顶连到原点的线的斜率大于等于 的楼顶连到原点的线的斜率,就说明 挡住了 。那么我们就用线段树来维护每个区间不考虑区间外的楼的答案以及最大的斜率,现在来考虑一下如何合并两个区间(子树)的答案。首先,左子树维护的区间的答案肯定不会被影响,但是右边的区间可能会有一部分被阻挡,所以我们直接递归处理一下右区间的答案。这样子单次修改+查询的复杂度是 的。

  1. #include <iostream>
  2. #include <cstdio>
  3. int n, m;
  4. struct Segtree {
  5. Segtree *ch[2];
  6. int ansv;
  7. double maxv;
  8. Segtree() {
  9. maxv = ansv = 0;
  10. ch[0] = ch[1] = NULL;
  11. }
  12. } *root;
  13. inline int read() {
  14. register int x = 0;
  15. register char ch = getchar();
  16. while(!isdigit(ch)) ch = getchar();
  17. while(isdigit(ch)) {
  18. x = x * 10 + ch - '0';
  19. ch = getchar();
  20. }
  21. return x;
  22. }
  23. void Build(Segtree *&o, int l, int r) {
  24. o = new Segtree;
  25. if(l == r) return;
  26. int mid = (l + r) >> 1;
  27. Build(o -> ch[0], l, mid);
  28. Build(o -> ch[1], mid + 1, r);
  29. }
  30. int calc(Segtree *o, int l, int r, double v) {
  31. if(l == r) return o -> maxv > v;
  32. int mid = (l + r) >> 1;
  33. if(o -> ch[0] -> maxv <= v) return calc(o -> ch[1], mid + 1, r, v);
  34. else return calc(o -> ch[0], l, mid, v) + o -> ansv - o -> ch[0] -> ansv;
  35. }
  36. void Modify(Segtree *o, int l, int r, int w, double k) {
  37. if(l == r) {
  38. o -> maxv = k;
  39. o -> ansv = 1;
  40. return;
  41. }
  42. int mid = (l + r) >> 1;
  43. if(w <= mid) Modify(o -> ch[0], l, mid, w, k);
  44. else Modify(o -> ch[1], mid + 1, r, w, k);
  45. o -> maxv = std::max(o -> ch[0] -> maxv, o -> ch[1] -> maxv);
  46. o -> ansv = o -> ch[0] -> ansv + calc(o -> ch[1], mid + 1, r, o -> ch[0] -> maxv);
  47. }
  48. int main() {
  49. n = read();
  50. m = read();
  51. Build(root, 1, n);
  52. while(m--) {
  53. int x = read(), y = read();
  54. Modify(root, 1, n, x, double(y) / double(x));
  55. printf("%d\n", root -> ansv);
  56. }
  57. return 0;
  58. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注