动态开点线段树样例不对求助

P3372 【模板】线段树 1

SegmentTree_ @ 2024-01-02 23:12:02

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define sum(x) tr[x].sum
#define ls(x) (tr[x].lc)
#define rs(x) (tr[x].rc)
#define lazy(x) (tr[x].lazy)
const int N = 1e5+5;
struct node{
    int lc, rc;
    ll sum, lazy;
}tr[N << 3];
int cnt = 1;
int n, q;
ll x;
void pushup(int k){
    sum(k) = sum(ls(k)) + sum(rs(k));
}
void pushdown(int k, int l, int r){
    if (lazy(k)){
        if (!ls(k)) ls(k) = ++cnt;
        if (!rs(k)) rs(k) = ++cnt;
        lazy(ls(k)) += lazy(k);
        lazy(rs(k)) += lazy(k);
        int mid = (l + r) >> 1;
        sum(ls(k)) += (mid - l + 1) * lazy(k);
        sum(rs(k)) += (r - mid) * lazy(k);
        lazy(k) = 0;
    }
}
void build(int &k, int l, int r, int v, int x){
    if (!k) k = ++cnt;
    if (l == r){
        sum(k) = x;
    }
    else{
        int mid = (l + r) >> 1;
        if (v <= mid) build(ls(k), l, mid, v, x);
        else build(rs(k), mid + 1, r, v, x);
        pushup(k);
    }
}
void add(int &k, int l, int r, int L, int R, int x){
    if (!k) k = ++cnt;
    if (L <= l && R >= r){
        lazy(k) += x;
        sum(k) += (r - l + 1) * x;
    }
    else{
        pushdown(k, l, r);
        int mid = (l + r) >> 1;
        if (L <= mid) add(ls(k), l, mid, L, R, x);
        if (R > mid) add(rs(k), mid + 1, r, L, R, x);
        pushup(k);  
    }

}
ll query(int k, int l, int r, int L, int R){
    if (!k) return 0;
    if (L <= l && R >= r) return sum(k);
    pushdown(k, l, r);
    int mid = (l + r) >> 1;
    ll res = 0;
    if (L <= mid) res += query(ls(k), l, mid, L, R);
    if (R > mid) res += query(rs(k), mid + 1, r, L, R);
    return res;
}
int main(){
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> q;
    for (int i = 1;i <= n;i++){
        cin >> x;
        int tmp = 1;
        build(tmp, 1, n, i, x);
    }
    while (q--){
        int op;
        cin >> op;
        if (op == 1){
            int L, R, x;
            cin >> L >> R >> x;
            int tmp = 1;
            add(tmp, 1, n, L, R, x);
        }
        else{
            int L, R;
            cin >> L >> R;
            cout << query(1, 1, n, L, R) << '\n';
        }
    }
    return 0;
} 

by Masna_Kimoyo @ 2024-01-02 23:26:21

别的不说,谁让你开八倍空间了

两倍空间就可以,这是动态开点的优势


by cmaths @ 2024-01-03 07:08:23

这 build 给我看懵了。


by Bingxiu @ 2024-01-03 07:08:56

@cmaths +1


by Bingxiu @ 2024-01-03 07:09:53

@tianyu_awa 你家 build 是一个一个节点加的(抽象)


by Bingxiu @ 2024-01-03 07:15:06

似乎看起来没什么问题???


by Bingxiu @ 2024-01-03 07:16:42

@tianyu_awa ?样例哪里不对了,我测了一下没问题啊


by cmaths @ 2024-01-03 07:20:21

好像也没问题,毕竟是动开线段树,不过为什么不直接用 add


by 2Bxzj @ 2024-01-03 10:15:14

@tianyu_awa 虽然我是蒟蒻,但是我认为整个程序中只build建树一次就可以了

void builded (int u, int l, int r)
{
    int x = u << 1, y = u << 1 | 1;
    tr[u].l = l, tr[u].r = r;
    if(l == r)
    {
        tr[u].he = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    builded(x, l, mid);
    builded(y, mid + 1, r);
    tr[u].he = tr[x].he + tr[y].he; //he 从tr[u].l到tr[u].r整个区间的和
    return;
}

这样写的话,只需要在询问前建树一次(build(1, 1, n))


by SegmentTree_ @ 2024-01-03 16:28:39

@Bingxiu ?


by SegmentTree_ @ 2024-01-03 16:31:19

@Bingxiu 好吧是我看错了


|