线段树

线段树就是一棵二叉树,用于求区间修改,区间查询,预处理的时间复杂度为o(nlogn),查询的时间复杂度为o(mlogn)。

在区间修改上,如果每次都进行单点修改,那么修改一次的时间复杂度是o((r-l+1)logn),这样可能会t,所以可以用lazy标记进行操作。就是懒操作。

当区间下置到一个节点时,其区间范围已经在题目要求的修改范围内了,那此时我们可以直接只修改这个点,不修改下面的点,做个标记,然后向上更新值。等到下一次修改如果要求修改上次修改范围内更小的区间时,将标记向它的左son和右son传递,并把这个点的标记删掉,向上更新值。

这是洛谷线段树模板题绿标题:

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
#define int long long
const int N = 1e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;
vector<int> vt[N];
int n, q, m;
int f[4 * N], a[N], lazy1[4 * N], lazy2[4 * N];
//更新标记值
void tag(int k, int l, int mid, int r) {
    f[2 * k] = (lazy2[k] * f[2 * k] % m + ((mid - l + 1) * lazy1[k]) % m) % m;
    f[2 * k + 1] = (lazy2[k] * f[2 * k + 1] % m + ((r - mid) * lazy1[k]) % m) % m;
    lazy2[2 * k] = (lazy2[2 * k] * lazy2[k]) % m;
    lazy2[2 * k + 1] = (lazy2[2 * k + 1] * lazy2[k]) % m;
    lazy1[2 * k] = ((lazy1[2 * k] * lazy2[k]) % m + lazy1[k]) % m;
    lazy1[2 * k + 1] = ((lazy1[2 * k + 1] * lazy2[k]) % m + lazy1[k]) % m;
    lazy1[k] = 0; lazy2[k] = 1;
}
//建树
void build(int k, int l, int r) {
    lazy2[k] = 1; lazy1[k] = 0;
    if (l == r) {
        f[k] = a[l] % m;
        return;
    }
    int mid = (l + r) >> 1;
    build(2 * k, l, mid);
    build(2 * k + 1, mid + 1, r);
    f[k] = (f[2 * k] + f[2 * k + 1]) % m;
}
//加法操作
void add(int k, int l, int r, int x, int y, int val) {
    if (l >= x && r <= y) {
        f[k] = (f[k] + ((r - l + 1) * val) % m) % m;
        lazy1[k] = (lazy1[k] + val) % m;
        return;
    }
    int mid = (l + r) >> 1;
    tag(k, l, mid, r);
    if (x <= mid)add(2 * k, l, mid, x, y, val);
    if (y > mid)add(2 * k + 1, mid + 1, r, x, y, val);
    f[k] = (f[2 * k] + f[2 * k + 1]) % m;
}
//乘法操作
void mul(int k, int l, int r, int x, int y, int val) {
    if (l >= x && r <= y) {
        f[k] = (f[k] * val) % m;
        lazy2[k] = (lazy2[k] * val) % m;
        lazy1[k] = (lazy1[k] * val) % m;
        return;
    }
    int mid = (l + r) >> 1;
    tag(k, l, mid, r);
    if (x <= mid)mul(2 * k, l, mid, x, y, val);
    if (y > mid)mul(2 * k + 1, mid + 1, r, x, y, val);
    f[k] = (f[2 * k] + f[2 * k + 1]) % m;
}
//查询操作
int check(int k, int l, int r, int x, int y) {
    if (l >= x && r <= y) return f[k];
    int mid = (l + r) >> 1;
    tag(k, l, mid, r);
    int ans1 = 0, ans2 = 0;
    if (x <= mid)ans1 = check(2 * k, l, mid, x, y);
    if (y > mid)ans2 = check(2 * k + 1, mid + 1, r, x, y);
    return (ans1 % m + ans2 % m) % m;
}
void solve() {
    cin >> n >> q >> m;
    for (int i = 1; i <= n; i++)cin >> a[i];
    build(1, 1, n);
    while (q--) {
        int op;
        cin >> op;
        if (op == 2) {
            int x, y, k;
            cin >> x >> y >> k;
            add(1, 1, n, x, y, k);
        }
        else if (op == 1) {
            int x, y, k;
            cin >> x >> y >> k;
            mul(1, 1, n, x, y, k);
        }
        else if (op == 3) {
            int x, y;
            cin >> x >> y;
            int res = check(1, 1, n, x, y);
            cout << res % m << "\n";
        }
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)solve();
    return 0;
}

 

那么多行,wa后调试真的会疯。。。

posted @ 2023-07-30 21:37  DLSQS  阅读(51)  评论(0)    收藏  举报