树状数组学习笔记
树状数组的基本操作这里就不再赘述(反正是笔记,我自己也记得)
单点修改,区间查询:
例题:树状数组1
int lowbit(int x){return (x&-x);}
struct bit{
int c[N];
void add(int x,int v){for(;x<=n;x+=lowbit(x))c[x]+=v;}
int query(int x){
int res=0;
for(;x;x-=lowbit(x))res+=c[x];
return res;
}
};
区间修改,单点查询:
例题:树状数组2
这个实现十分的简单,我们只需要一颗树状数组维护一个差分序列就可以了。
struct bit2{
int c[N];
void add(int l,int r,int v){
r++;
for(;l<=n;l+=lowbit(l))c[l]+=v;
for(;r<=n;r+=lowbit(r))c[r]-=v;
}
int query(int x){
int res=0;
for(;x;x-=lowbit(x))res+=c[x];
return res;
}
};
下面是的才是我想记录的:
区间修改,区间查询:
考虑和区间修改,单点查询一样,维护一个差分序列。
令原序列为 aa , 差分序列为 bb 。
我们的区间查询 \sum_{i=1}^n a_i∑i=1nai
根据差分的定义,我们区间查询转化为了 \sum_{i=1}^r \sum_{j=1}^i b_j∑i=1r∑j=1ibj
拆开柿子推导一下:
\sum_{i=1}^r \sum_{j=1}^i b_j∑i=1r∑j=1ibj
= b_1+2b_2+3b_3+4b_4……=b1+2b2+3b3+4b4……
= \sum_{i=1}^r b_i\times (r-i+1)=∑i=1rbi×(r−i+1)
= \sum_{i=1}^r b_i\times (r+1)-\sum_{i=1}^r b_i\times i=∑i=1rbi×(r+1)−∑i=1rbi×i
于是我们开两个树状数组维护 b_ibi 和 b_i\times ibi×i
例题:线段树1
struct bit3{
int b[N],c[N];
void add(int l,int r,int v){
r++;int vl=l*v,vr=r*v;
for(;l<=n;l+=lowbit(l)){
b[l]+=v;
c[l]+=vl;
}
for(;r<=n;r+=lowbit(r)){
b[r]-=v;
c[r]-=vr;
}
}
int query(int x){
int a1=0,a2=0,j=x,i=x;
for(;i;i-=lowbit(i))a1+=b[i];
for(;j;j-=lowbit(j))a2+=c[j];
return a1*(x+1)-a2;
}
};
你以为这就结束了?不!
这才刚刚开始。
二维树状数组,单点修改,平面区间查询
例题:二维树状数组1
struct bit4{
int c[M][M];
void add(int x,int y,int v){
for(;x<=n;x+=lowbit(x)){
int i=y;
while(i<=n)c[x][i]+=v,i+=lowbit(i);
}
}
int query(int x,int y){
int res=0;
for(;x;x-=lowbit(x))for(int i=y;i;i-=lowbit(i))res+=c[x][i];
return res;
}
};
二维树状数组,平面区间修改,单点查询
和一维树状数组一样,二维前缀和的操作代码里有,其他的都一样。
例题:二维树状数组2
struct bit5{
int c[M][M];
void ad(int x,int y,int v){
for(;x<=n;x+=lowbit(x)){
int i=y;
while(i<=n)c[x][i]+=v,i+=lowbit(i);
}
}
void add(int x,int y,int v){
ad(x,y,v);ad(x+1,y,-v);ad(x,y+1,-v);ad(x+1,y+1,v);
}
int query(int x,int y){
int res=0;
for(;x;x-=lowbit(x))for(int i=y;i;i-=lowbit(i))res+=c[x][i];
return res;
}
};
最后,我们来看大BOSS
你准备好了吗?
二维树状数组,平面区间修改,平面区间查询
和一维基本思路是一致的,我们先推推柿子
\sum_{i=1}^x \sum_{j=1}^y a_{i,j}∑i=1x∑j=1yai,j
=\sum_{i=1}^x \sum_{j=1}^y \sum_{k=1}^i \sum_{t=1}^j b_{k,t}=∑i=1x∑j=1y∑k=1i∑t=1jbk,t
(将柿子展开,跳一步。)
=(x+1)(y+1)\sum_{i=1}^x \sum_{j=1}^y b_{i,j}- (x+1)\sum_{i=1}^x \sum_{j=1}^y b_{i,j}\times j- (y+1)\sum_{i=1}^x \sum_{j=1}^y b_{i,j}\times i+ \sum_{i=1}^x \sum_{j=1}^y b_{i,j}\times ij=(x+1)(y+1)∑i=1x∑j=1ybi,j−(x+1)∑i=1x∑j=1ybi,j×j−(y+1)∑i=1x∑j=1ybi,j
