线段树
线段树就是一棵二叉树,用于求区间修改,区间查询,预处理的时间复杂度为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后调试真的会疯。。。

浙公网安备 33010602011771号