線段樹區間取膜438D - The Child and Sequence
阿新 • • 發佈:2021-07-16
438D - The Child and Sequence
題面
長度為n的非負整數數列,3種操作
- 求\([L,R]\)所有數的和。
- 將\([L,R]\)中所有數都\(mod \ x\)。
- 將\(a_i\)修改為\(v\)。
\(n,m≤100000\)
題解
對於一段區間,如果取模的數比這段區間所有的數都大,那取模就是沒有意義的,就是說,如果取模的數比區間最大的數還大,那麼就不用取模了,所以我們線上段樹裡再記錄一個區間最大值
考慮每次取模,對於每一個數\(x\),取模\(y\),\(x \ mod \ y\)的值必然比\(y\)小,如果\(y\)小於\(\frac{x}{2}\),那x就變得小於\(\frac{x}{2}\)
那麼就是說\(x\)每次取模都會變得比\(\frac{x}{2}\)小,就是說,對於一個數\(x\),有效的取\(mod\)最多進行\(logx\)次,一共只會進行\(nlogn\)次取模,那麼就算對所有的數取模,這個時間複雜度都是可以接受的
那麼我們對於每個區間記錄一個最大值,如果取模的數大於最大值,就不管,如果小於最大值,就暴力取模
程式碼
struct BIT { struct node { int l, r; long long sum; int mx; } tr[N << 2]; void push_up(int p) { tr[p].mx = max(tr[p << 1].mx, tr[p << 1 | 1].mx); tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum; } void build(int p, int l, int r, vector<int>& a) { tr[p].l = l, tr[p].r = r; if (l == r) { tr[p].sum = tr[p].mx = a[l]; return; } int mid = l + r >> 1; build(p << 1, l, mid, a); build(p << 1 | 1, mid + 1, r, a); push_up(p); } int ask(int p, int l, int r) { if (tr[p].l >= l && tr[p].r <= r) return tr[p].sum; int mid = tr[p].l + tr[p].r >> 1; if (mid >= r) return ask(p << 1, l, r); if (mid < l) return ask(p << 1 | 1, l, r); return ask(p << 1, l, r) + ask(p << 1 | 1, l, r); } void change(int p, int k, int v) { if (tr[p].l == k && tr[p].r == k) { tr[p].sum = tr[p].mx = v; return; } int mid = tr[p].l + tr[p].r >> 1; if (mid >= k) change(p << 1, k, v); else if (mid < k) change(p << 1 | 1, k, v); push_up(p); } void changemod(int p, int l, int r, int mod) { if (tr[p].l == tr[p].r) { tr[p].sum = tr[p].mx = tr[p].sum % mod; return; } int mid = tr[p].l + tr[p].r >> 1; if (mid >= l && tr[p << 1].mx >= mod) changemod(p << 1, l, r, mod); if (mid < r && tr[p << 1 | 1].mx >= mod) changemod(p << 1 | 1, l, r, mod); push_up(p); } } bit; int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; vector<int> a(n + 1); for (int i = 1; i <= n; ++i) cin >> a[i]; bit.build(1, 1, n, a); while (m--) { int op; cin >> op; if (op == 1) { int l, r; cin >> l >> r; cout << bit.ask(1, l, r) << '\n'; } else if (op == 2) { int l, r, mod; cin >> l >> r >> mod; bit.changemod(1, l, r, mod); } else { int k, v; cin >> k >> v; bit.change(1, k, v); } } return 0; }