题目传送门
sol:题目读完就知道是线段树,gcd满足结合律。操作2也好想到差分,但是不会修改后维护gcd。看了题解发现还是差分,这个差分用的妙啊;
- 线段树+差分
#include "bits/stdc++.h" using namespace std; const int MAXN = 1e5 + 10; struct Tree{ int l, r; int sum; int sub; int gcd; } segTree[MAXN * 4]; int arr[MAXN]; void build(int i, int l, int r) { segTree[i].l = l; segTree[i].r = r; if (l == r) return; int mid = l + r >> 1; build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r); } void update(int i, int index, int val) { if (segTree[i].l == segTree[i].r) { segTree[i].sum = val; segTree[i].sub = max(val, -val); segTree[i].gcd = segTree[i].sub; return; } int mid = segTree[i].l + segTree[i].r >> 1; if (index <= mid) update(i << 1, index, val); else update(i << 1 | 1, index, val); segTree[i].sum = segTree[i << 1].sum + segTree[i << 1 | 1].sum; segTree[i].sub = max(segTree[i << 1].sub, segTree[i << 1 | 1].sub); segTree[i].gcd = __gcd(segTree[i << 1].gcd, segTree[i << 1 | 1].gcd); } int query(int i, int op, int l, int r) { if (l <= segTree[i].l && r >= segTree[i].r) { if (op == 1) return segTree[i].sum; if (op == 2) return segTree[i].sub; if (op == 3) return segTree[i].gcd; } int mid = segTree[i].l + segTree[i].r >> 1; int ans = 0; if (op == 1) { if (l <= mid) ans += query(i << 1, 1, l, r); if (r > mid) ans += query(i << 1 | 1, 1, l, r); } else if (op == 2) { if (l <= mid) ans = max(ans, query(i << 1, 2, l, r)); if (r > mid) ans = max(ans, query(i << 1 | 1, 2, l, r)); } else { if (l <= mid) ans = __gcd(ans, query(i << 1, 3, l, r)); if (r > mid) ans = __gcd(ans, query(i << 1 | 1, 3, l, r)); } return ans; } int main() { int n, m; scanf("%d%d", &n, &m); build(1, 1, n); for (int i = 1; i <= n; i++) scanf("%d", &arr[i]); for (int i = n; i >= 1; i--) { arr[i] -= arr[i - 1]; update(1, i, arr[i]); } while (m--) { int op, l, r, x; scanf("%d", &op); if (op == 1) { scanf("%d%d%d", &l, &r, &x); arr[l] += x; update(1, l, arr[l]); if (r + 1 <= n) { arr[r + 1] -= x; update(1, r + 1, arr[r + 1]); } } else if (op == 2) { scanf("%d%d", &l, &r); if (l == r) puts("0"); else printf("%d\n", query(1, 2, l + 1, r)); } else { scanf("%d%d", &l, &r); if (l == r) printf("%d\n", query(1, 1, 1, l)); else printf("%d\n", __gcd(query(1, 1, 1, l), query(1, 3, l + 1, r))); } } return 0; }