区间加法和区间询问,很明显是用线段树啦!
线段树通过懒标记实现了 $log$ 的时间复杂度,保证了在 $3e5$ 范围内不会超时。这道题重点是输出是非负的余数,所以要这样输出:
cout << (query(1, x, y) % (k + 1) + (k + 1)) % (k + 1) << "\n";
而不是:
cout << abs(query(1, x, y) % (k + 1)) << "\n";
代码如下:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 5;
struct node {int l, r, sum, tag;
}tr[N << 2];
int n, m, op, x, y, k, a[N];
inline void updata(int p){tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum;
}
inline void downdata(int p){int mid = (tr[p].l + tr[p].r) >> 1;if(!tr[p].tag) return ;tr[p << 1].sum += (mid - tr[p].l + 1) * tr[p].tag;tr[p << 1].tag += tr[p].tag;tr[p << 1 | 1].sum += (tr[p].r - mid) * tr[p].tag;tr[p << 1 | 1].tag += tr[p].tag;tr[p].tag = 0;
}
inline void build(int p, int l, int r){tr[p].l = l, tr[p].r = r;if(l == r){tr[p].sum = a[r];return ;}int mid = (l + r) >> 1;build(p << 1, l, mid);build(p << 1 | 1, mid + 1, r);updata(p);
}
inline void add(int p, int l, int r, int v){if(tr[p].l >= l && tr[p].r <= r){tr[p].sum += (tr[p].r - tr[p].l + 1) * v;tr[p].tag += v;return ;}downdata(p);int mid = (tr[p].l + tr[p].r) >> 1;if(l <= mid) add(p << 1, l, r, v);if(r > mid) add(p << 1 | 1, l, r, v);updata(p);
}
inline int query(int p, int l, int r){if(tr[p].l >= l && tr[p].r <= r) return tr[p].sum;downdata(p);int mid = (tr[p].l + tr[p].r) >> 1;int cnt = 0;if(l <= mid) cnt += query(p << 1, l, r);if(r > mid) cnt += query(p << 1 | 1, l, r);return cnt;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);cin >> n;int m = n;for(int i = 1; i <= n; i++) cin >> a[i];build(1, 1, n);while(m--){cin >> op >> x >> y >> k;if(!op) add(1, x, y, k);else cout << (query(1, x, y) % (k + 1) + (k + 1)) % (k + 1) << "\n";}return 0;
}
管理大大求过!