『題解』Codeforces-438D The Child and Sequence
阿新 • • 發佈:2022-01-25
Description
- 給定數列,區間查詢和,區間取模,單點修改。
- \(n, m \leq 10^5, a_i\le 10^9\)。
Solution
思路與 花神遊歷各國 很像。
假設現在是 \(x\bmod p\):
- 若 \(x < p\):不用模;
- 若 \(x\ge p\):設 \(x = pq + r(0\le r < p)\),則 \(q\ge 1\),於是操作後得到的數 \(r < \dfrac{x}{2}\)。
對於第一種情況,記錄區間最大值 \(mx\),當 \(mx < p\) 時直接 return
對於第二種情況,數 \(n\) 至多經過 \(\log n\) 次取模操作就會變成 \(1\),所以區間取模直接暴力遞迴即可。
一開始共可以被模 \(n \log a\) 次,然後單點修改可以使一個數多被模 \(\log\) 次,所以一共是 \((n + m)\log a\) 次。
Code
// 18 = 9 + 9 = 18. #include <iostream> #include <cstdio> #define Debug(x) cout << #x << "=" << x << endl #define int long long using namespace std; const int MAXN = 1e5 + 5; int a[MAXN]; #define lson pos << 1 #define rson pos << 1 | 1 struct tree { int l, r, mx, sum; }t[MAXN << 2]; void pushup(int pos) { t[pos].mx = max(t[lson].mx, t[rson].mx); t[pos].sum = t[lson].sum + t[rson].sum; } void build(int pos, int l, int r) { t[pos].l = l, t[pos].r = r; if (l == r) { t[pos].mx = t[pos].sum = a[l]; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(pos); } void update_val(int pos, int dis, int k) { int l = t[pos].l, r = t[pos].r; if (l == r) { t[pos].mx = t[pos].sum = k; return; } int mid = (l + r) >> 1; if (dis <= mid) { update_val(lson, dis, k); } else { update_val(rson, dis, k); } pushup(pos); } void update_mod(int pos, int L, int R, int k) { if (t[pos].mx < k) { return; } int l = t[pos].l, r = t[pos].r; if (l == r) { t[pos].mx %= k; t[pos].sum %= k; return; } int mid = (l + r) >> 1; if (L <= mid) { update_mod(lson, L, R, k); } if (R > mid) { update_mod(rson, L, R, k); } pushup(pos); } int query(int pos, int L, int R) { int l = t[pos].l, r = t[pos].r; if (L <= l && r <= R) { return t[pos].sum; } int mid = (l + r) >> 1, res = 0; if (L <= mid) { res = query(lson, L, R); } if (R > mid) { res += query(rson, L, R); } return res; } signed main() { int n, m; scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) { scanf("%lld", a + i); } build(1, 1, n); while (m--) { int op, l, r, k; scanf("%lld%lld%lld", &op, &l, &r); if (op == 1) { printf("%lld\n", query(1, l, r)); } else if (op == 2) { scanf("%lld", &k); update_mod(1, l, r, k); } else { update_val(1, l, r); } } return 0; }