萌新求助线段树,玄关

P3372 【模板】线段树 1

Typed_SIGTERM @ 2024-10-26 08:36:50

输出 11 8 16,不知道哪里错了 /kk

#include <iostream>
using namespace std;

namespace Solution {
using LL = long long;
constexpr int N = 1e5 + 5, NODE = N << 2; // 线段树是完全二叉树,节点数 < 深度 * 4
int n;
LL a[N], tree[NODE], flag[NODE];

void dbg() {
  cerr << "tree: ";
  for (int i = 1; i < n * 2; ++i) cerr << tree[i] << ' ';
  cerr << "\nflag: ";
  for (int i = 1; i < n * 2; ++i) cerr << flag[i] << ' ';
  cerr << '\n';
}

inline int left(int x) { return x << 1; }
inline int right(int x) { return (x << 1) + 1; }

void pushDown(int root, int l, int r) {
  cerr << "push " << root << ' ' << l << ' ' << r << '\n';
  if (!flag[root]) return;
  tree[root] += flag[root] * (r - l + 1); // [l, r] 区间内都加了 flag[root]
  if (l != r) { // 需要下发标记
    flag[left(root)] += flag[root];
    flag[right(root)] += flag[root];
  }
  flag[root] = 0;
}

inline void pushUp(int x) {
  tree[x] = tree[left(x)] + tree[right(x)];
}

void build(int root, int l, int r) {
  if (l == r) {
    tree[root] = a[l];
  } else {
    int mid = (l + r) >> 1;
    build(left(root), l, mid);
    build(right(root), mid + 1, r);
    pushUp(root);
  }
}

void update(int l, int r, LL value, int root = 1, int start = 1, int end = n) {
  cerr << "update " << l << '~' << r << ", " << value << ", " << root << ", " << start << '~' << end << '\n';
  if (l <= start && r >= end) {
    // @todo optimize
    tree[root] += value * (end - start + 1);
    flag[root] += value;
   } else {
    pushDown(root, start, end);
    int mid = (start + end) >> 1;
    if (l <= mid)
      update(l, r, value, left(root), start, mid);
    if (r > mid)
      update(l, r, value, right(root), mid + 1, end);
    pushUp(root);
  }
  dbg();
}

LL query(int l, int r, int root = 1, int start = 1, int end = n) {
  cerr << "query\n";
  if (l <= start && r >= end) return tree[root];
  pushDown(root, start, end);
  if (start == end) return tree[root];
  int ans = 0, mid = (start + end) >> 1;
  if (l <= mid) ans += query(l, r, left(root), start, mid);
  if (r > mid) ans += query(l, r, right(root), mid + 1, end);
  dbg();
  return ans;
}

void solve() {
  int m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i)
    cin >> a[i];
  build(1, 1, n);
  while (m--) {
    int op, x, y, k;
    cin >> op >> x >> y;
    switch (op) {
      case 1:
        cin >> k;
        update(x, y, k);
        break;
      case 2:
        cout << query(x, y) << '\n';
        break;
    }
    cerr << '\n';
  }
}

}  // namespace Solution

int main() {
  ios::sync_with_stdio(0);
  cin.tie(nullptr);
  Solution::solve();
  return 0;
}

(祝各位 CSP 2024 rp++)


by __Louis__ @ 2024-10-26 08:40:20

query 哪里出问题了,因该不需要特判l==r


by __Louis__ @ 2024-10-26 08:42:11

还有一点,下发标记了以后就要更新值,否则更新会慢。

建议写 add_tag 函数。

@ZihanHu


by __Louis__ @ 2024-10-26 08:46:22

void add_tag(int x,int l,int r,int tg){
    tree[x].da+=(r-l+1)*tg;
    tree[x].tg+=tg;
}
void push_down(int x,int l,int r){
    if(tree[x].tg){
        int mid=(l+r)>>1;
        add_tag(ls(x),l,mid,tree[x].tg);
        add_tag(rs(x),mid+1,r,tree[x].tg);
        tree[x].tg=0;
    }
}

这是我平时写 push_down 时候的写法,加了 tag 以后要及时更新值,否则会出问题。


by Typed_SIGTERM @ 2024-10-26 08:53:56

@Louis 感谢大佬,祝您 CSP rp++

现在有 10pts 了!

(看了一下第一个点的数据,又是最后一个查询寄了 xwx

8 10
640 591 141 307 942 58 775 133 
2 1 5
2 3 8
2 3 6
2 5 8
2 4 8
1 4 8 60
2 1 6
2 5 8
1 3 7 15
1 2 6 86

ans:

2621
2356
1448
1908
2215
2859
2388

|