区间树状数组

具体参数见注释.首先是设定:

  • 设定一:朴素树状数组不能沟进行足够快的区间更新
  • 设定二:我本人懒得写线段树

于是我们有了“可以足够快进行区间更新”的树状数组。

  • 对于任意前N项和(记为SUM(N))都应当有SUM(N)=A[1]+A[2]+A[3]+........+A[N]。
  • 设C[K]=A[K]-A[K-1]都应该有:SUM[C[N]]=A[N]:
    证明:
    A:SUM[C[N]]=C[1]+C[2]+C[3]+C[4]+.......+C[N];
    B:SUM[C[N]]=-A[0](A[0]不存在有意义的值,认为是0)+A[1]+(A[2]-A[1])+(A[3]-A[2]).......+(A[N]-A[N-1])=A[N]
  • 推论:SUM[A[N]]=A[1]+A[2]+A[3]+.....+A[N]=SUM(C[1])+SUM(C[2])+SUM(C[3])+......+SUM(C[N])
    展开得:=SUM[A[N]]=N*C[1]+(N-1)*C[2]+......+C[N]->进行一个巧妙地变换,我们可以把系数对应起来:
    SUM[A[N]]=N*SUM[C[N]]-0*C[1]-1*C[2]-........(N-2)*C[N-1];

  • 于是另外设定一个数组:C2并且认为C2[K]=(K-1)*C[K]于是,我们得到了一种数组求和的等效替代,对原数组的仇和操作作都可以被分解为对于C和C2的求和操作。
    (未完待续。。。。)
 1 /*
 2 *常量MAXN用于设定树状数组的尺寸大小
 3 */
 4 const long long MAXN=500233;
 5 class TreeLikeArray
 6 {
 7     public:
 8 /*
 9 *数组c1用来储存A[i]-A[i-1];
10 */
11         long long c1[MAXN];
12 /*
13 *数组c2用来储存(A[i]-A[i-1])*(i-1);
14 *或认为用于储存(i-1)*c1[i];
15 *两种实现方式完全等价
16 */
17         long long c2[MAXN];
18 /*
19 *树状数组的常规操作,参数要求传入数组并指明更新位置,以及更新参数。
20 *树状数组基础底层操作
21 */
22         void add(long long array[],long long pos,long long key)
23     {
24         while(pos<MAXN)
25         {
26             array[pos]+=key;
27             pos+=pos&(-pos);
28         }
29     }
30 /*
31 *特别树状数组单点更新操作,要求传入位置和参数
32 */
33     void add(long long pos,long long key)
34     {
35         add(c1,pos,key);
36         add(c1,pos+1,-key);
37         add(c2,pos,(pos-1)*key);
38         add(c2,pos+1,-pos*key);
39     }
40 /*
41 *特别树状数组多点更新操作,要求传入起始位置、终止位置和参数
42 *该操作将会使得[pos1,pos2]闭区间内所有元素得到更新
43 */
44     void add(long long pos1,long long pos2,long long key)
45     {
46         add(c1,pos1,key);
47         add(c1,pos2+1,-key);
48         add(c2,pos1,(pos1-1)*key);
49         add(c2,pos2+1,-pos2*key);
50     }
51 /*
52 *树状数组的常规操作,参数要求传入数组并指明求和位置
53 *树状数组基础底层操作
54 */
55     long long getSum(long long array[],long long pos)
56     {
57         long long ret=0;
58         while(pos>0)
59         {
60             ret+=array[pos];
61             pos-=pos&(-pos);
62         }return ret;
63     }
64 /*
65 *从起始节点到目标节点闭区间求和[0,i]
66 */
67     long long getSum(long long pos)
68     {
69         return pos*getSum(c1,pos)-getSum(c2,pos);
70     }
71 /*
72 *求[pos1,pos2]闭区间内元素和
73 */
74     long long getSum(long long pos1,long long pos2)
75     {
76         return getSum(pos2)-getSum(pos1-1);
77     }
78 /*
79 *求pos单个元素的值
80 */
81     long long getSingle(long long pos)
82     {
83         return getSum(pos,pos);
84     }
85 };  
原文地址:https://www.cnblogs.com/rikka/p/7359185.html