지원 간격은 펜윅 트리를 변경
원칙
배열 용 \ (a \) 와 \ (a \) 차이 \ (C \) , 명백하게 \ (c [I] = A
[i]를 -a [I-1] \) 다음 어레이 A의 이 접두사
\ (\ sum_ {내가 = 1 } ^ N {A_I} = C [1] + (c [1] + C [2]) + ... (c [1] + C [2] +. .. + C [N]) \
) 상기 :
.. \ (\ sum_ 1 = {I} ^ {A_I} = N-C [. 1] + N-C * 2 * (1-N-) + ... + C [N] * N- (
N + 1) \) 괄호 안에 배치
\ (\ sum_ I = {1 } ^ {N} A_I = C [1] * N + C [2 * N + ... + C [N] * N- (c [
1] * (1-1) + (C) [2] * (2-1) + ... + C는 [N * (N-1)) \) 은 IS
(\ \ sum_ ^ {난 = 1} N {A_I} = N * \ sum_ {I = 1} ^ N {C [I]} - \ sum_ {I = 1} ^ N {C [I] * (I-1 )} \)은
따라서 프리픽스 두 배열 유지할 필요성 유지 차동 접두사 \ (c를 [I] \) 와 (\. (1-I) * C [I]를 \) 유지 보수에 대응 (\ sum_ {\ I . (1)} ^ {N- = C [I]} \) \ (\ sum_. (1)} ^ {N-I가 = {(I-. 1) * C [I]} \)
는 차동 배열 트리 본원에 사용 된 바와 같이, 두 배열 접두사와 유지 보수로 선정됐다 \ (TR \) 및\ (TR1 \) .
실현
: 먼저 두 가지 기본 작업 트리 기본 배열 취소 범위 쿼리 와 단조로운 문의 . 펜윅 트리 유지 보수 및 접두사의 사용 :
- 쿼리 간격 \ (\ {텍스트 쿼리} (K) \) , 1과 K 사이의 프리픽스 \ (\ sum_ {I = 1 } ^ {A K [I]} \)
- 단일 지점 수정 \ (\ 추가 {텍스트} (K, X)를 \) , \ (A [K] + = X \)
그런 다음이 문서에 대한 지원과 수정 수지상 배열은 다음과 같습니다
1. 간격 수정 \ (\ 추가 {텍스트} (L, R, K) \) (L하고 포괄적 R), 작업이 동일하다을 (\ \ {ADD1 문자 (L, X)} \) , \ (\ {텍스트} ADD1 (R & LT +. (1), -X-) \) 와 \ (\ 텍스트 {ADD2} ( L (L-1) * X) \) , \ (\ {텍스트} ADD2 (R & LT + 1, R & LT * (-. X)) \) (차동 속성 정의)
2. 쿼리 간격 \ (querysum (K) \) , 동작은 동일하다 \ (K * \ 텍스트 쿼리 1} {(K) * K-\ 텍스트 쿼리 1} {(K) \)
운영
기본 펜윅 나무
달성하기 위해 \ (O (로그 (N) ) \) 단일 지점 범위 및 쿼리를 수정합니다.
그것은 하나의 수정, 쿼리 간격, 메시지의 단일 지점을 지원합니다.
int n, m;
ll a[maxn];
ll tr[maxn]; //树状数组1用于维护差分前缀和$\sum_{i=1}^n{c[i]}$
ll tr1[maxn]; //树状数组2用于维护差分前缀和$\sum_{i=1}^n{(i-1)*c[i]}$
int lowbit(int x) { return x & -x; }
void add(ll tr[], int l, ll k) {
for (int i = l; i <= n; i += lowbit(i)) tr[i] = (tr[i] + k) % mod;
}
ll query(ll tr[], int r) {
ll res = 0;
for (int i = r; i; i -= lowbit(i)) res = (res + tr[i]) % mod;
return res;
}
초기화
void init(int nn) {
n = nn + 2;//防止空间越界
for (int i = 0; i <= n; i++) tr[i] = tr1[i] = 0;
}
간격 수정
//[l,r]区间修改+x
void add(int l, int r, int x) {
add(tr, l, x);
add(tr, r + 1, -x);
add(tr1, l, 1ll * (l - 1) * x);
add(tr1, r + 1, 1ll * r * (-x));
}
간격 질문
쿼리 \ (\ sum_ {I}. ^ 1 = KA [I] \) , 즉 질의 \ (\ [1, K] ) 프리픽스 및 내부
//区间查询原数组sum(a[1,k])
ll querysum(int k) {
return (1ll * query(tr, k) * k) - query(tr1, k);
}
간격 수정
에서는 (a [1] ... \ [R] \) 간격 더하기 \ (X \) .
//[l,r]区间修改+x
void add(int l, int r, int x) {
add(tr, l, x);
add(tr, r + 1, -x);
add(tr1, l, 1ll * (l - 1) * x);//防止暴int
add(tr1, r + 1, 1ll * r * (-x));
}
복잡도 분석
펜윅 트리 본질 개의 프리픽스와 공간 세번 간격 길이이고, 차분을 유지하도록 \ (O (N-3 *) \)
시간 복잡도 :
다음과 같은 동작이다를 \ (O (로그 (N) ) \) :
- 게다가 간격으로 X
- 간격 질문
- 메시지의 단일 지점
- X와 단조 플러스
세그먼트 트리에 비해 공간 복잡도 \ (O (4 * N) \) 작은
동시에 복잡성.
프로그래밍 복잡성 거의 (그들은 열심히 orz 있습니다)
통합 템플릿
#define judge
// Author: oceanlvr
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
static int faster_iostream = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
return 0;
}();
const int maxn = 1e6 + 10;
const int mod = 772002 + 233;
int n, m;
ll a[maxn];
ll tr[maxn]; //树状数组1
ll tr1[maxn]; //树状数组2
int lowbit(int x) { return x & -x; }
void add(ll tr[], int l, ll k) {
for (int i = l; i <= n; i += lowbit(i)) tr[i] = (tr[i] + k) % mod;
}
ll query(ll tr[], int r) {
ll res = 0;
for (int i = r; i; i -= lowbit(i)) res = (res + tr[i]) % mod;
return res;
}
//[l,r]区间修改+x
void add(int l, int r, int x) {
add(tr, l, x);
add(tr, r + 1, -x);
add(tr1, l, 1ll * (l - 1) * x);
add(tr1, r + 1, (1ll * r * (-x)%mod+mod)%mod);
}
//区间查询原数组sum(a[1,k])
ll querysum(int k) {
return (((1ll * query(tr, k) * k) % mod - query(tr1, k) % mod) % mod + mod) %
mod;
}
void init(int nn) {
n = nn + 2;
for (int i = 0; i <= n; i++) tr[i] = tr1[i] = 0;
}
/*------------------------------------------------------------------------------*/
//按题目要求区间[l,r]修改 [l+1,r]+d,[l,l]+a0,[r+1,r+1]-前面两个的和
void addad(int l, int r, int a0, int d) {
add(l, l, a0); //单点l上+a0
if (l + 1 <= r) add(l + 1, r, d); //区间[l+1,r] +d
add(r + 1, r + 1,
(-(a0 + (1ll * (r - l) * d)) % mod + mod) % mod); //单点r+1 -前面两个的和
}
//区间查询原数组sum(a[1,k])
int queryad(int k) { return querysum(k); }
int op;
int main() {
#ifndef judge
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i],a[i]%=mod;
init(n);
for (int i = 0; i < m; i++) {
cin >> op;
if (op == 1) {
int x, y;
cin >> x >> y;
//(y+1)y/2
//对[x,x+y-1]加上一个-1
int l = x, r = min(x + y - 1, n);
addad(l, r, y, -1);
} else if (op == 2) {
int x;
cin >> x;
cout << (a[x] + queryad(x)) % mod << endl;
}
}
return 0;
}
참고 링크 : 펜윅 트리 플러스 간격 연산 순서