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 好吧是我看错了