刚学的 折腾了一上午终于弄好了
树状数组几种用法(不全):
①单点修改区间查询(基本)
②区间修改单点查询(差分)
③区间修改区间查询(维护贡献)
我只特意整理了第三种用法
下方代码
#include
#include
#define db delta_before
#define da delta_after
#define ll long long
using namespace std;
int n,q;
long long a[200005],delta_before[200005],delta_after[200005];//a是原数的树状数组 da和db是维护贡献的树状数组
long long get(ll *array,int k){
long long tmp=0;
for(;k;k-=(k&-k))tmp+=array[k];
return tmp;
}
void add(ll *array,int k,ll w){
for(;k<=n;k+= (k&-k))array[k]+=w;
return ;
}
long long gets(int k){
long long ans=0;
ans+=get(a,k);
ans+=get(db,k);
ans+=k*(get(da,n)-get(da,k));
return ans;
}//gets用于取出 1到k的前缀和
void adds(int k,ll w){
add(db,k,k*w);
add(da,k,w);
return ;
}//将他在前面和后面的贡献都更新
int main(){
cin>>n>>q;
int tmp;
for(int i=1;i<=n;++i){
scanf("%d",&tmp);
for(int j=i;j<=n;j+=(j&-j))
a[j]+=tmp;
}
char opt[2];int l,r;ll w;
while(q--){
scanf("%s%d%d",opt,&l,&r);
if(opt[0]=='C'){
scanf("%lld",&w);
adds(r,w);
if(l>1) //如果是0 会无限循环
adds(l-1,-w);
}
else {
ll ans1=gets(r);
ll ans2=0;
if(l>1)
ans2=gets(l-1);
printf("%lld\n",ans1-ans2);
}
}
}
可以去交一下这几个板子
codevs 1082 poj 3468 luogu线段树1
因为懒就不建超链了
接下来是重头戏
二维树状数组实现矩形修改、矩形查询
著名的——上帝造题的七分钟
tyvj 1716 或者 bzoj 3132(权限题)
(不知道为什么tyvj这几天评测炒鸡慢..)
最后两个点死活过不去 在研究
先把能过八个点的代码发上来了
如下
//tyvj 1716 上帝造题的七分钟
//by 曹有毒
#include
#include
const int N=2050;
#define up(x) x+=(x&-x)
#define down(x) x-=(x&-x)
using namespace std;
int in[N][N],out[N][N],up[N][N],down[N][N];
int n,m;
int get(int array[][N],int i, int j){
int tmp=0;
for(int x=i;x;x-=(x&(-x)))
for(int y=j;y;y-=(y&(-y)))
tmp+=array[x][y];
return tmp;
}
int getss(int x,int y){
if(x*y==0)return 0;
int tmp=0;
tmp+=get(in,x,y)+x*y*(get(out,n,m)+get(out,x,y)-get(out,x,m)-get(out,n,y) );
tmp+=y*(get(up,x,m)-get(up,x,y));
tmp+=x*(get(down,n,y)-get(down,x,y) );
return tmp;
}
void add(int array[][N],int x,int y,int w){
for(int i=x;i<=n;i+=(i&(-i)))
for(int j=y;j<=m;j+=(j&(-j)))
array[i][j]+=w;
return ;
}
void adds(int i,int j,int w){
if(i*j==0)return ;
add(in,i,j,i*j*w);
add(down,i,j,j*w);
add(up,i,j,i*w);
add(out,i,j,w);
return;
}
int main(){
scanf("%*S%d%d",&n,&m);
int a,b,c,d,dlt,ans;
char opt[2];
while( scanf("%s%d%d%d%d",opt,&a,&b,&c,&d)==5 ){
if(opt[0]=='L'){
scanf("%d",&dlt);
adds(a-1,b-1,dlt);
adds(a-1,d,-dlt);
adds(c,b-1,-dlt);
adds(c,d,dlt);
}
else {
ans=getss(c,d)+getss(a-1,b-1)-getss(a-1,d)-getss(c,b-1);
printf("%d\n",ans);
}
}
return 0;
}
比较悲剧的 调的时候死活过不去 然后发现我分不清行和列..好多年以来一直没分清…
还是自己画个矩形推一遍式子比较好吧 根本记不住的