树状数组(区间修改,单点查询)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e6+5;
ll c[maxx];
ll n,m;
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll w)
{
while(x<=n)
{
c[x]+=w;
x+=lowbit(x);
}
}
ll sum(ll x)//差分数组求前缀和即为原数组
{
ll sum=0;
while(x>0)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
ll t,i,l,r,x,temp=0,k;
scanf("%lld %lld",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%lld",&t);
add(i,t-temp);//用树状数组存储本身数组的差分形式
temp=t;
}
while(m--)
{
scanf("%lld",&k);
if(k==1)
{
scanf("%lld %lld %lld",&l,&r,&x);
add(l,x);
add(r+1,-x);//差分数组变换的规则
}
if(k==2)
{
scanf("%lld",&x);
printf("%lld\n",sum(x));
}
}
/*
5 3
1 4 7 6 5
以此为例
差分数组为
1 3 3 -1 -1
1、先是1进入 c[]为 1 1 0 1 0
2、3进入 c[]为 1 4 0 4 0
3、3进人 c[]为 1 4 3 7 0
4、-1进人 c[]为 1 4 3 6 0
5、-1进人 c[]为 1 4 3 6 -1
*/
return 0;
}
树状数组(区间修改,区间查询)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e6+5;
ll a[maxx],b[maxx],n;
ll k,l,r,w;
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll *t,ll x,ll w)
{
while(x<=n)
{
t[x]+=w;
x+=lowbit(x);
}
}
ll sum(ll *t,ll x)
{
ll ans=0;
while(x>0)
{
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
ll q,i,t,temp=0,sum1,sum2;
cin>>n>>q;
for(i=1;i<=n;i++)
{
//cin>>t;
scanf("%lld",&t);
add(a,i,t-temp);
add(b,i,(i-1)*(t-temp));
temp=t;
}
while(q--)
{
scanf("%lld",&k);
//cin>>k;
if(k==1)
{
//cin>>l>>r>>w;
scanf("%lld %lld %lld",&l,&r,&w);
add(a,l,w);
add(a,r+1,-w);
add(b,l,w*(l-1));
add(b,r+1,-w*r);
}
else if(k==2)
{
//cin>>l>>r;
scanf("%lld %lld",&l,&r);
sum1=(l-1)*sum(a,l-1)-sum(b,l-1);
sum2=r*sum(a,r)-sum(b,r);
// cout<<(r*sum(a,r)-(l-1)*sum(a,l-1))-(sum(b,r)-sum(b,l-1))<<endl;
printf("%lld\n",sum2-sum1);
}
}
/*对于题目给的例子
5 10
2 6 6 1 1
它的差分数组为
2 4 0 -5 0
在代码中对应的a[]中的过程
1、2进入时为 2 2 0 2 0
2、4进入时为 2 6 0 6 0
3、0进入时为 2 6 0 6 0
4、-5进入时为2 6 0 1 0
5、0进入时为 2 6 0 1 0
在代码中对应的b[]产生过程
(i-1)*(t-temp)的原数组
0 4 0 -15 0
1、0进入时为 0 0 0 0 0
2、4进入时为 0 4 0 4 0
3、0进入时为 0 4 0 4 0
4、-15进入时 0 4 0 -11 0
5、0进入时为 0 4 0 -11 0
最重要的公式将差分树状数组直接和区间和联系起来
n*(c[1]+c[2]+...+c[n])-(0*c[1]+1*c[2]+...+(n-1)*c[n])
在代码中a[i]对应的是c[i]
在代码中b[i]对应的是(i-1)*c[i]
在最后求和同时应用这两个数组
*/
return 0;
}
树状数组(区间修改,单点查询2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e6+5;
ll a[maxx],c[maxx];
//用数组正常情况下做的话会超时,用树状数组做
int main()
{
ll n,m,i,r,l,x,k;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
c[1]=a[1];
for(i=2;i<=n;i++)
{
c[i]=a[i]-a[i-1];
}
while(m--)
{
scanf("%lld",&k);
if(k==1)
{
scanf("%lld %lld %lld",&l,&r,&x);
a[l]+=x;
a[r+1]+=x;
}
if(k==2)
{
ll sum=0;
scanf("%lld",&x);
for(i=1;i<=x;i++)
{
sum+=c[i];
}
printf("%lld\n",sum);
}
}
return 0;
}
二维树状数组(单点修改和区间查询)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=5e3+5;
ll n,m,t;
ll tree[maxx][maxx];
ll lowbit(ll x)
{
return x&(-x);
}
void add(ll x,ll y,ll w)
{
while(x<=n)
{
int ty=y;
while(ty<=m)
{
tree[x][ty]+=w;
ty+=lowbit(ty);
}
x+=lowbit(x);
}
}
ll sum(int x,int y)
{
ll ans=0;
while(x>0)
{
int ty=y;
while(ty>0)
{
ans+=tree[x][ty];
ty-=lowbit(ty);
}
x-=lowbit(x);
}
return ans;
}
int main()
{
int i,j;
cin>>n>>m;
// for(i=1;i<=n;i++)
// {
// for(j=1;j<=m;j++)
// {
// cin>>t;
// add(i,j,t);
// }
// }
while(scanf("%lld",&t)!=EOF)
{
int a,b,c,d,w;
if(t==1)
{
cin>>a>>b>>w;
add(a,b,w);
}
else if(t==2)
{
cin>>a>>b>>c>>d;
cout<<sum(c,d)-sum(a-1,d)-sum(c,b-1)+sum(a-1,b-1)<<endl;
}
}
return 0;
}