이야기
입력 샘플
5 1012
34 5678 9 10
Q44
Q 1 10
Q2
4100 3 6 3
Q2 4
샘플 출력
4
55
9
15
대답
- 이 질문에는 간격 수정 및 간격 쿼리가 포함됩니다. 물론 라인 세그먼트 트리를 사용하여 수행 할 수 있지만 트리 어레이를 사용하여 트리 어레이로 해결할 수있는 문제를 해결할 수 있습니다. 라인을 사용할 필요가 없습니다. 트리 배열을 이해하지 못한다면 먼저 여기를 살펴 보거나 간단한 정수 문제, 차분 배열 (트리 배열은 O (logn) 단일 포인트를 지원함)이라는 아이디어를 사용할 수 있습니다. 수정, 간격 쿼리)
- "C lrd"는 A [l], A [l + 1], ..., A [r]에 d를 추가하는 것을 의미합니다. 차이 배열로 변환 할 수 있습니다. 범위에 대해서는 차이 배열 만 수정하면됩니다. 간격을 수정할 수 있도록 두 끝점 b [l] + = c, b [r + 1]-= c;
- "Q lr"은 쿼리 시퀀스에서 숫자 l ~ r의 합계를 의미합니다. 원래 배열을 차이 배열로 변환 한 후에는 차이 배열의 접두사 합이 원래 배열의 간격 합이 아니라 원래 배열의 값이기 때문에 간격 쿼리를 수행 할 수 없습니다. 원래 배열?
4. 위 공식을 도출 한 후 두 개의 트리 배열 만 유지하면된다는 것을 발견했습니다. 하나는 a [i] -a [i-1]이고 다른 하나는 i * (a [i] -a [i -1]), 이와 같이 요소 군 [1, x]의 구간 합을 구할 수 있으며, 완전히 변형 된 접두사와 아이디어를 이용하여 원래 배열의 임의 구간을 구할 수있다. 트리 배열의 기본 작업으로
암호
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll n, m;
ll a[N]; //原数组
ll tr1[N]; //b[i]的前缀和数组
ll tr2[N]; //i*b[i]的前缀和数组
ll lowbit(ll x) {
return x & -x;
}
void add(ll tr[], ll x, ll c) {
for (ll i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
ll sum(ll tr[], ll x) {
ll res = 0;
for (ll i = x; i; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
ll prefix_sum(ll x) {
return sum(tr1, x) * (x + 1) - sum(tr2, x);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) add(tr1, i, a[i] - a[i - 1]);
for (int i = 1; i <= n; i++) add(tr2, i, i * (a[i] - a[i - 1]));
while (m--) {
string op;
int l, r, d;
cin >> op >> l >> r;
if (op == "Q") {
cout << prefix_sum(r) - prefix_sum(l - 1) << endl;
} else {
cin >> d;
add(tr1, l, d), add(tr1, r + 1, -d);
add(tr2, l, l * d), add(tr2, r + 1, -(r + 1) * d);
}
}
return 0;
}