【牛客小白月赛16】H 小阳的贝壳

Practice Link

题意:
维护一个序列\(a_i\),支持三种操作:

  • \(1\;l\;r\;x\),给区间\([l, r]\)的所有数\(+x\)
  • \(2\;l\;r\) 询问区间\([l, r]\)所有相邻贝壳颜色值的差的绝对值
  • \(3\;l\;r\) 询问区间\([l, r]\)所有数的最大公约数

思路:
其实最难的第三个操作怎么维护。
考虑

\[\begin{eqnarray*} gcd(a, b) = gcd(a, b - a) \end{eqnarray*} \]

那么可以扩展一下即为

\[\begin{eqnarray*} gcd(a, b, c) = gcd(a, b - a, c - b) \end{eqnarray*} $$, 那么我们在线段树中维护一个后向差分数组,那么区间修改就变成了单点修改,就很容易维护区间$gcd$了,止于第二个操作,其实就是差分的绝对值的最大值。 注意最后$gcd$要取绝对值。 代码: ```c++ #include <bits/stdc++.h> using namespace std; #define ll long long #define N 100010 int n, q, a[N], b[N]; int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } struct SEG1 { struct node { ll sum; int cnt, lazy, l, r, Max; node() { sum = cnt = lazy = 0; l = r = Max = 0; } void add(int x) { sum += 1ll * cnt * x; lazy += x; l += x; r += x; } node operator + (const node &other) const { node res = node(); res.sum = sum + other.sum; res.cnt = cnt + other.cnt; res.l = l; res.r = other.r; res.Max = max(Max, other.Max); res.Max = max(res.Max, abs(r - other.l)); return res; } }t[N << 2], res; void build(int id, int l, int r) { if (l == r) { t[id] = node(); t[id].sum = a[l]; t[id].cnt = 1; t[id].l = t[id].r = a[l]; return; } int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); t[id] = t[id << 1] + t[id << 1 | 1]; } void down(int id) { int &lazy = t[id].lazy; if (!lazy) return; t[id << 1].add(lazy); t[id << 1 | 1].add(lazy); lazy = 0; } void update(int id, int l, int r, int ql, int qr, int x) { if (l >= ql && r <= qr) { t[id].add(x); return; } int mid = (l + r) >> 1; down(id); if (ql <= mid) update(id << 1, l, mid, ql, qr, x); if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, x); t[id] = t[id << 1] + t[id << 1 | 1]; } node query(int id, int l, int r, int ql, int qr) { if (l >= ql && r <= qr) return t[id]; int mid = (l + r) >> 1; down(id); if (ql <= mid && qr > mid) { node L = query(id << 1, l, mid, ql, qr); node R = query(id << 1 | 1, mid + 1, r, ql, qr); return L + R; } else if (ql <= mid) { return query(id << 1, l, mid, ql, qr); } else if (qr > mid) { return query(id << 1 | 1, mid + 1, r, ql, qr); } else { assert(0); } } }seg1; struct SEG2 { int t[N << 2]; void build(int id, int l, int r) { if (l == r) { t[id] = b[l]; return; } int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); t[id] = gcd(t[id << 1], t[id << 1 | 1]); } void update(int id, int l, int r, int x, int v) { if (l == r) { t[id] += v; return; } int mid = (l + r) >> 1; if (x <= mid) update(id << 1, l, mid, x, v); else update(id << 1 | 1, mid + 1, r, x, v); t[id] = gcd(t[id << 1], t[id << 1 | 1]); } int query(int id, int l, int r, int ql, int qr) { if (ql > qr) return 0; if (l >= ql && r <= qr) return t[id]; int mid = (l + r) >> 1; int res = 0; if (ql <= mid) res = gcd(res, query(id << 1, l, mid, ql, qr)); if (qr > mid) res = gcd(res, query(id << 1 | 1, mid + 1, r, ql, qr)); return res; } }seg2; int main() { while (scanf("%d%d", &n, &q) != EOF) { for (int i = 1; i <= n; ++i) { scanf("%d", a + i); b[i] = a[i] - a[i - 1]; } seg1.build(1, 1, n); seg2.build(1, 1, n); int op, l, r, x; while (q--) { scanf("%d%d%d", &op, &l, &r); switch(op) { case 1 : scanf("%d", &x); seg1.update(1, 1, n, l, r, x); seg2.update(1, 1, n, l, x); if (r < n) seg2.update(1, 1, n, r + 1, -x); break; case 2 : seg1.res = seg1.query(1, 1, n, l, r); printf("%d\n", seg1.res.Max); break; case 3 : seg1.res = seg1.query(1, 1, n, l, l); printf("%d\n", abs(gcd(seg1.res.sum, seg2.query(1, 1, n, l + 1, r)))); break; } } } return 0; } ```\]

posted @ 2019-07-13 08:38  Dup4  阅读(293)  评论(0编辑  收藏  举报