数组数组用于维护区间信息,简洁的几行的代码可以单点操作/区间查询,或者区间操作与单点查询。
注意:维护区间信息时,查询ask(x)返回的是x的值。进行的单点操作,查询ask(x)返回的是1~x的前缀和
虽然功能小于线段树,但是在相同功能的实现上,两者复杂度(但是线段树常数大)差不多。线段树
我们先介绍第一个功能
先看一下树状数组的图
我们观察出他的几个性质:
我们如何求最低位1呢?
假如我们对x+k,那么他的祖先们都需要,去祖先的更新方法就是+lowbit
void add(int x,int k)
{
for (int i=x; i<=n; i+=i&-i)t[i]+=k;
}
那么我们从t[x]一直减最低位1,累加到t[0]即可
ll ask(int x)
{
ll ans=0;
for (int i=x; i; i-=i&-i)ans+=t[i];
return ans;
}
#include
using namespace std;
#define ll long long
const int N = 5e5 + 10;
int a[N],t[N];
int n;
void add(int x,int k)
{
for (int i=x; i<=n; i+=i&-i)t[i]+=k;
}
ll ask(int x)
{
ll ans=0;
for (int i=x; i; i-=i&-i)ans+=t[i];
return ans;
}
int main()
{
int m,p,x,y;
cin>>n>>m;
for (int i=1; i<=n; ++i)cin>>a[i],add(i,a[i]);
while (m--)
{
cin>>p>>x>>y;
if (p==1)
{
add(x,y);
}
else if (p==2)
{
cout<
代码没什么区别
int b[N];
int n;
void add(int x,int k)
{
for (int i=x; i<=n; i+=i&-i)b[i]+=k;
}
ll ask(int x)
{
ll ans=0;
for (int i=x; i; i-=i&-i)ans+=b[i];
return ans;
}
#include
using namespace std;
#define ll long long
const int N = 5e5 + 10;
int b[N];
int n;
void add(int x,int k)
{
for (int i=x; i<=n; i+=i&-i)b[i]+=k;
}
ll ask(int x)
{
ll ans=0;
for (int i=x; i; i-=i&-i)ans+=b[i];
return ans;
}
int main()
{
int m,p,x,y,k;
cin>>n>>m;
for (int i=1; i<=n; ++i)cin>>x,add(i,x),add(i+1,-x);
while (m--)
{
cin>>p;
if (p==1)
{
cin>>x>>y>>k;
add(x,k),add(y+1,-k);
}
else if (p==2)
{
cin>>x;
cout<
#include
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
const int N = 2e5 + 10;
int t[N],a[N];
int n,q;
void update(int x,int w)
{
t[x]=a[x]=w;//修改时该点也要修改
while(x<=n)//遍历x及其所有树上祖先进行修改
{
int lx=x&-x;//lowbit(x)
for(int i=1; i=l)ans=max(ans,t[r]),r=lx-1;//查询时,如果[x-lowbit[x]+1,x]在范围内,直接获取,否则,取出a[x],x--
else ans=max(ans,a[r]),r--;
}
return ans;
}
void mysolve()
{
while(cin>>n>>q)
{
for(int i=1; i<=n; ++i)cin>>a[i],update(i,a[i]);
int x,y;
char c;
while(q--)
{
cin>>c>>x>>y;
if(c=='Q')cout<> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}