지원 간격은 펜윅 트리를 변경

지원 간격은 펜윅 트리를 변경

원칙

배열 용 \ (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 \) .

실현

: 먼저 두 가지 기본 작업 트리 기본 배열 취소 범위 쿼리단조로운 문의 . 펜윅 트리 유지 보수 및 접두사의 사용 :

  1. 쿼리 간격 \ (\ {텍스트 쿼리} (K) \) , 1과 K 사이의 프리픽스 \ (\ sum_ {I = 1 } ^ {A K [I]} \)
  2. 단일 지점 수정 \ (\ 추가 {텍스트} (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;
}

참고 링크 : 펜윅 트리 플러스 간격 연산 순서

추천

출처www.cnblogs.com/adameta/p/12406227.html