单点修改&区间查询
最普通的树状数组
实现用lowbitlowbitlowbit的优秀性质
原理很简单
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 500005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll a[MAXN],tr[MAXN];
ll n,m;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll lowbit(ll x)
{
return x&(-x);
}
O3 inline void add(ll x,ll y)
{
while (x<=n)tr[x]+=y,x+=lowbit(x);
}
O3 inline ll query(ll x)
{
ll y=0;
while (x)y+=tr[x],x-=lowbit(x);
return y;
}
O3 inline ll ask(ll x,ll y)
{
return query(y)-query(x-1);
}
O3 int main()
{
//freopen("readin.txt","r",stdin);
n=read(),m=read();
fo(i,1,n)a[i]=read(),add(i,a[i]);
while (m--)
{
ll z=read(),x=read(),y=read();
if (z==1)add(x,y);
else printf("%lld\n",ask(x,y));
}
return 0;
}
区间修改&单点查询
实现这个的思路比较巧妙
做一个差分,设b[i]=a[i]−a[i−1]b[i]=a[i]-a[i-1]b[i]=a[i]−a[i−1],那么∑i=1nb[i]=a[i]\sum^n_{i=1}b[i]=a[i]∑i=1nb[i]=a[i]
那么对于一个区间的修改[x,y][x,y][x,y]区间加kkk,相当于xxx位加kkk、y+1y+1y+1位减kkk
容易知道这是对的,在xxx前没有影响,从xxx开始才有贡献
用树状数组维护bbb就好了
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 500005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;++i)
#define O3 __attribute__((optimize("-O3")))
ll a[MAXN],tr[MAXN];
ll n,m;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll lowbit(ll x)
{
return x&(-x);
}
O3 inline void change(ll x,ll y)
{
while (x<=n)tr[x]+=y,x+=lowbit(x);
}
O3 inline ll query(ll x)
{
ll y=0;
while (x)y+=tr[x],x-=lowbit(x);
return y;
}
O3 int main()
{
//freopen("readin.txt","r",stdin);
n=read(),m=read();
fo(i,1,n)a[i]=read(),change(i,a[i]-a[i-1]);
while (m--)
{
ll z=read(),x,y;
if (z==1)
{
x=read(),y=read(),z=read();
change(x,z),change(y+1,-z);
}
else printf("%lld\n",query(read()));
}
return 0;
}
伪线段树树状数组
其实这个就是支持区间修改和区间查询的树状数组
对于一段区间查询[x,y][x,y][x,y],拆成[1,x−1][1,x-1][1,x−1]和[1,y][1,y][1,y],单独考虑[1,x][1,x][1,x]的答案即可
-
那么ans=∑i=1xa[i]=a[1]+a[2]+a[3]+...+a[x]ans=\sum^x_{i=1}a[i]=a[1]+a[2]+a[3]+...+a[x]ans=∑i=1xa[i]=a[1]+a[2]+a[3]+...+a[x]
-
=(b[1])+(b[1]+b[2])+(b[1]+b[2]+b[3])+...+(b[1]+b[2]+b[3]...+b[x])=(b[1])+(b[1]+b[2])+(b[1]+b[2]+b[3])+...+(b[1]+b[2]+b[3]...+b[x])=(b[1])+(b[1]+b[2])+(b[1]+b[2]+b[3])+...+(b[1]+b[2]+b[3]...+b[x])
-
=b[1]∗x+b[2]∗(x−1)+b[3]∗(x−2)+...+b[x]=b[1]*x+b[2]*(x-1)+b[3]*(x-2)+...+b[x]=b[1]∗x+b[2]∗(x−1)+b[3]∗(x−2)+...+b[x]
-
=x(b[1]+b[2]+b[3]+...+b[x])−(b[1]∗0+b[2]∗1+b[3]∗2+...+b[x]∗(x−1))=x(b[1]+b[2]+b[3]+...+b[x])-(b[1]*0+b[2]*1+b[3]*2+...+b[x]*(x-1))=x(b[1]+b[2]+b[3]+...+b[x])−(b[1]∗0+b[2]∗1+b[3]∗2+...+b[x]∗(x−1))
再设一个ccc数组,使c[i]=b[i]∗(i−1)c[i]=b[i]*(i-1)c[i]=b[i]∗(i−1)
那么[1,x][1,x][1,x]的和即为x∗query(b,x)−query(c,x)x*query(b,x)-query(c,x)x∗query(b,x)−query(c,x)
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 500005
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;++i)
#define O3 __attribute__((optimize("-O3")))
ll a[MAXN],tr[MAXN],tr1[MAXN];
ll n,m;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll lowbit(ll x)
{
return x&(-x);
}
O3 inline void change(ll *tr,ll x,ll y)
{
while (x<=n)tr[x]+=y,x+=lowbit(x);
}
O3 inline ll query(ll *tr,ll x)
{
ll y=0;
while (x)y+=tr[x],x-=lowbit(x);
return y;
}
O3 int main()
{
//freopen("readin.txt","r",stdin);
n=read(),m=read();
fo(i,1,n)a[i]=read(),change(tr,i,a[i]-a[i-1]),change(tr1,i,(a[i]-a[i-1])*(i-1));
while (m--)
{
ll z=read(),x,y;
if (z==1)
{
x=read(),y=read(),z=read();
change(tr,x,z),change(tr,y+1,-z);
change(tr1,x,z*(x-1)),change(tr1,y+1,-z*y);
}
else x=read(),y=read(),
printf("%lld\n",(y*query(tr,y)-(x-1)*query(tr,x-1))-(query(tr1,y)-query(tr1,x-1)));
}
return 0;
}