1 条题解

  • 1
    @ 2026-9-28 20:51:44

    线段树模板

    读完题目我们可以知道本题是区间修改区间查询
    不难想到线段树(毕竟都叫 线段树1 了)

    线段树思路

    开数组存线段树

    线段树要开4倍数组,因为每个节点都有至多两个子节点,编号为n的4倍
    struct Node {
    	int l, r;
    	ll sum, add;
    }tr[N << 2];
    
    区间修改需要懒标记来维护复杂度

    建树的函数build

    通过递归左右子节点来建树,保证树高为 log n
    void pushup (int u) {  //通过左右子节点计算父节点区间和
    	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    }
    void build(int u, int l, int r) {
    	tr[u] = {l, r};
    	if(l == r) {  //如果递归到叶子节点,直接赋值,结束递归
    		tr[u].sum = a[l];
    		return;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;  //将该节点二分,递归左右节点
    	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    	pushup(u);
    }
    

    区间修改modify

    同样递归遍历节点
    void pushdown(int u) {  //将懒标记传给子节点,更新子节点sum
    	if(tr[u].add) {
    		ll c = tr[u].add;
    		tr[u << 1].sum += (ll)(tr[u << 1].r - tr[u << 1].l + 1) * c;
    		tr[u << 1].add += c;
    		tr[u << 1 | 1].sum += (ll)(tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * c;
    		tr[u << 1 | 1].add += c;
    		tr[u].add = 0;  //清空父节点懒标记
    	}
    }
    void modify (int u, int l, int r, ll c) {
    	if(tr[u].l >= l && tr[u].r <= r) { //如果该节点完全在所修改区间内,更新sum,更新懒标记
      		tr[u].sum += (ll)(tr[u].r - tr[u].l + 1) * c;
    		tr[u].add += c;
    		return;//结束递归
    	}
    //否则继续递归
    	int mid = tr[u].l + tr[u].r >> 1;
    	pushdown(u);  //递归前保证sum为真实值
    	if(l <= mid) modify(u << 1, l, r, c);//如果修改区间覆盖到左子结点,递归左子结点
    	if(r > mid) modify(u << 1 | 1, l, r, c);//同理递归右子节点
    	pushup(u);
    }
    

    区间查询query

    ll query (int u, int l, int r) {
    	if(tr[u].l >= l && tr[u].r <= r) {
    		return tr[u].sum;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	pushdown(u);
    	ll ans = 0;
    	if(l <= mid) ans = query(u << 1, l, r);
    	if(r > mid) ans += query(u << 1 | 1, l, r);
    	return ans;
    }
    
    # include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    #define MID int mid = tr[u].l + tr[u].r >> 1
    const int N = 1e5 + 10;
    int n, m;
    int a[N];
    struct Node {
    	int l, r;
    	ll sum, add;
    }tr[N << 2];
    void pushup (int u) {
    	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    }
    void build(int u, int l, int r) {
    	tr[u] = {l, r};
    	if(l == r) {
    		tr[u].sum = a[l];
    		return;
    	}
    	MID;
    	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    	pushup(u);
    }
    void pushdown(int u) {
    	if(tr[u].add) {
    		ll c = tr[u].add;
    		tr[u << 1].sum += (ll)(tr[u << 1].r - tr[u << 1].l + 1) * c;
    		tr[u << 1].add += c;
    		tr[u << 1 | 1].sum += (ll)(tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * c;
    		tr[u << 1 | 1].add += c;
    		tr[u].add = 0;
    	}
    }
    void modify (int u, int l, int r, ll c) {
    	if(tr[u].l >= l && tr[u].r <= r) {
    		tr[u].sum += (tr[u].r - tr[u].l + 1) * c;
    		tr[u].add += c;
    		return;
    	}
    	MID;
    	pushdown(u);
    	if(l <= mid) modify(u << 1, l, r, c);
    	if(r > mid) modify(u << 1 | 1, l, r, c);
    	pushup(u);
    }
    ll query (int u, int l, int r) {
    	if(tr[u].l >= l && tr[u].r <= r) {
    		return tr[u].sum;
    	}
    	MID;
    	pushdown(u);
    	ll ans = 0;
    	if(l <= mid) ans = query(u << 1, l, r);
    	if(r > mid) ans += query(u << 1 | 1, l, r);
    	return ans;
    }
    int main () {
    	ios::sync_with_stdio(0), cin.tie(0);
    	cin >> n >> m;
    	for (int i = 1; i <= n; i ++) cin >> a[i];
    	build(1, 1, n);
    	while(m --) {
    		int op, l, r;
    		cin >> op >> l >> r;
    		if(op == 1) {
    			ll c;
    			cin >> c;
    			modify(1, l, r, c);
    		} else {
    			cout << query(1, l, r) << '\n';
    		}
    	}
    	return 0;
    }
    

    可以根据个人习惯更改

    • 1

    信息

    ID
    1195
    时间
    1000ms
    内存
    512MiB
    难度
    显示难度普及+/提高−
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者