传送门:https://loj.ac/problem/6029
【题解】
考虑如果有一些近似连续的段
比如 2 2 2 3 3 3,考虑在除3意义下,变成0 0 0 1 1 1,相当于整体-2
又:区间增加很容易造成这种段,所以我们猜测可以暴力维护
用一棵线段树即可。(好像真的能暴力维护啊 我不知道怎么证明复杂度)
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 4e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, a[M]; struct SMT { ll mx[M], mi[M], s[M], tag[M]; # define ls (x<<1) # define rs (x<<1|1) inline void up(int x) { s[x] = s[ls] + s[rs]; mx[x] = max(mx[ls], mx[rs]); mi[x] = min(mi[ls], mi[rs]); } inline void pushtag(int x, ll tg, int len) { mx[x] += tg; mi[x] += tg; s[x] += tg*len; tag[x] += tg; } inline void down(int x, int l, int r) { if(tag[x] == 0) return ; int mid = l+r>>1; pushtag(ls, tag[x], mid-l+1); pushtag(rs, tag[x], r-mid); tag[x] = 0; } inline void build(int x, int l, int r) { tag[x] = 0; if(l == r) { mx[x] = mi[x] = s[x] = a[l]; return ; } int mid = l+r>>1; build(ls, l, mid); build(rs, mid+1, r); up(x); } inline void edt(int x, int l, int r, int L, int R, int c) { if(L <= l && r <= R) { pushtag(x, c, r-l+1); return ; } down(x, l, r); int mid = l+r>>1; if(L <= mid) edt(ls, l, mid, L, R, c); if(R > mid) edt(rs, mid+1, r, L, R, c); up(x); } inline void div(int x, int l, int r, int L, int R, int d) { if(L <= l && r <= R) { ll A, B; if(mi[x] < 0) A = (mi[x] - d + 1) / d; else A = mi[x] / d; if(mx[x] < 0) B = (mx[x] - d + 1) / d; else B = mx[x] / d; if(mi[x] - A == mx[x] - B) { pushtag(x, A - mi[x], r-l+1); return ; } } down(x, l, r); int mid = l+r>>1; if(L <= mid) div(ls, l, mid, L, R, d); if(R > mid) div(rs, mid+1, r, L, R, d); up(x); } inline ll sum(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return s[x]; down(x, l, r); int mid = l+r>>1; ll ret = 0; if(L <= mid) ret += sum(ls, l, mid, L, R); if(R > mid) ret += sum(rs, mid+1, r, L, R); return ret; } inline ll gmin(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return mi[x]; down(x, l, r); int mid = l+r>>1; ll ret = 1e18; if(L <= mid) ret = min(ret, gmin(ls, l, mid, L, R)); if(R > mid) ret = min(ret, gmin(rs, mid+1, r, L, R)); return ret; } }T; int main() { int Q, opt, l, r, x; cin >> n >> Q; for (int i=1; i<=n; ++i) scanf("%d", a+i); T.build(1, 1, n); while(Q--) { scanf("%d%d%d", &opt, &l, &r); ++l, ++r; if(opt == 1) { scanf("%d", &x); T.edt(1, 1, n, l, r, x); } else if(opt == 2) { scanf("%d", &x); T.div(1, 1, n, l, r, x); } else if(opt == 3) printf("%lld\n", T.gmin(1, 1, n, l, r)); else printf("%lld\n", T.sum(1, 1, n, l, r)); } return 0; }
时间: 2024-10-13 17:09:06