小阳的贝壳

这里最难维护的应该是区间了,但是我们有一个结论,所以这一步可以转换为维护整个序列的差分。

对于操作一:我们只要对端点的值增加,对端点的值减小

对于操作二:我们只要得到差分数组里的绝对值最大值就行了。

对于操作三:我们首先要得到,然后得到这一段差分序列的,然后再于求一个即为答案。

对一整颗线段树我们只要维护三个值:区间、区间绝对值最大、区间和,我们就可以完成上面的三个操作了。

然后对某些线段树上的操作特判防止数组越界即可。

#include <bits/stdc++.h>
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

ll maxn[N << 2], gd[N << 2], sum[N << 2], a[N];

void push_up(int rt) {
  sum[rt] = sum[ls] + sum[rs];
  gd[rt] = __gcd(gd[ls], gd[rs]);
  maxn[rt] = max(maxn[ls], maxn[rs]);
}

void build(int rt, int l, int r) {
  if (l == r) {
    gd[rt] = abs(a[l]);
    maxn[rt] = abs(a[l]);
    sum[rt] = a[l];
    return ;
  }
  build(lson);
  build(rson);
  push_up(rt);
}

void update(int rt, int l, int r, int L, int R, int x) {
  if (l >= L && r <= R) {
    sum[rt] += x;
    gd[rt] = abs(sum[rt]);
    maxn[rt] = abs(sum[rt]);
    return ;
  }
  if (L <= mid) update(lson, L, R, x);
  if (R > mid)  update(rson, L, R, x);
  push_up(rt);
}

ll query_max(int rt, int l, int r, int L, int R) {
  if (l >= L && r <= R) {
    return maxn[rt];
  }
  ll ans = 0;
  if (L <= mid) ans = max(ans, query_max(lson, L, R));
  if (R > mid)  ans = max(ans, query_max(rson, L, R));
  return ans;
}

ll query_sum(int rt, int l, int r, int L, int R) {
  if (l >= L && r <= R) {
    return sum[rt];
  }
  ll ans = 0;
  if (L <= mid) ans += query_sum(lson, L, R);
  if (R > mid)  ans += query_sum(rson, L, R);
  return ans;
}

ll query_gcd(int rt, int l, int r, int L, int R) {
  if (l >= L && r <= R) {
    return gd[rt];
  }
  ll ans = 0;
  if (L <= mid) ans = __gcd(ans, query_gcd(lson, L, R));
  if (R > mid)  ans = __gcd(ans, query_gcd(rson, L, R));
  return ans;
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  for (int i = n; i >= 1; i--) {
    a[i] -= a[i - 1];
  }
  build(1, 1, n);
  for (int i = 1; i <= m; i++) {
    int op, l, r, x;
    cin >> op >> l >> r;
    if (op == 1) {
      cin >> x;
      update(1, 1, n, l, l, x);
      if (r + 1 <= n) {
        update(1, 1, n, r + 1, r + 1, -x);
      }
    }
    else if (op == 2) {
      if (l == r) {
        cout << "0\n";
      }
      else {
        cout << query_max(1, 1, n, l + 1, r) << "\n";
      }
    }
    else {
      if (l == r) {
        cout << query_sum(1, 1, n, 1, r) << "\n";
      }
      else {
        ll cur = query_sum(1, 1, n, 1, l);
        cout << __gcd(cur, query_gcd(1, 1, n, l + 1, r)) << "\n";
      }
    }
  }
  return 0;
}