题解:P13979 数列分块入门 4
区间加法和区间询问,很明显是用线段树啦!
线段树通过懒标记实现了 $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;
}
管理大大求过!
浙公网安备 33010602011771号