https://scut.online/p/77
线段树的一种奇怪的应用,暴力区间更新,每次update直接pushdown到底部,然后从维护底部。这样下次update的时候假如提前遇到底部就很快返回了。每个节点更新60次,单次更新nlogn。更新完毕之后每次update都是几乎一个log就返回了。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXM = 100000;
ll a[MAXM + 5];
ll st[(MAXM << 2) + 5];
bool zero[(MAXM << 2) + 5];
const int mod = 1e9 + 7;
inline void push_up(int o) {
st[o] = (st[o << 1] + st[o << 1 | 1]) % mod;
zero[o] = (zero[o << 1] && zero[o << 1 | 1]);
}
void build(int o, int l, int r) {
if(l == r) {
st[o] = a[l] % mod;
zero[o] = (a[l] == 0);
} else {
int m = (l + r) >> 1;
build(o << 1, l, m);
build(o << 1 | 1, m + 1, r);
push_up(o);
}
}
void update(int o, int l, int r, int ql, int qr) {
if(l == r) {
a[l] >>= 1;
st[o] = a[l] % mod;
zero[o] = (a[l] == 0);
return;
}
if(ql <= l && r <= qr && zero[o])
return;
int m = (l + r) >> 1;
if(ql <= m)
update(o << 1, l, m, ql, qr);
if(qr >= m + 1)
update(o << 1 | 1, m + 1, r, ql, qr);
push_up(o);
}
ll query(int o, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
return st[o];
} else {
int m = (l + r) >> 1;
ll ans = 0;
if(ql <= m)
ans = query(o << 1, l, m, ql, qr);
if(qr >= m + 1)
ans += query(o << 1 | 1, m + 1, r, ql, qr);
return ans % mod;
}
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T, n, m;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n ; ++i)
scanf("%lld", &a[i]);
build(1, 1, n);
char op[20];
int l, r;
for(int i = 1; i <= m; ++i) {
scanf("%s%d%d", op, &l, &r);
if(op[0] == 'U') {
update(1, 1, n, l, r);
} else {
printf("%lld
", query(1, 1, n, l, r));
}
}
}
return 0;
}