题目大意:
反正都是中文的,可以自己去读。把题目的意思抽象化就是,给你一串数(50000)个,然后进行最多40000次操作,操作内容包括:改变某一个数的值,查询该数组的一个连续区间
分析:
如果用普遍的方法,那么,每次改变某一个数的值时间复杂度O(1);查询一次,时间复杂度O(n);如果查询太多,肯定就超时了。解决办法就是引入树状数组,让查询区间和和改变某一数的值的时间复杂度都变为O(logn);这样就不会超时了。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[50050]={0};
int tree[50050]={0};
int n;
int lowbit(int x)//tree[x]为a[x]~a[x-lowbit(x)+1]的和。
{
return (-x)&x;
}
void add(int i,int y)//给a[i]增加y
{
a[i]+=y;
while(i<=n)
{
tree[i]+=y;
i+=lowbit(i);
}
}
int f(int x)//计算[1,x]的值
{
int s=0;
while(x>=1)
{
s=s+tree[x];
x=x-lowbit(x);
}
return s;
}
int sum(int l,int r)//计算[l,r]的值
{
return f(r)-f(l)+a[l];
}
int main()
{
int tt;
cin>>tt;
for(int test=1;test<=tt;test++)
{
memset(tree,0,sizeof(tree));
memset(a,0,sizeof(a));
cin>>n;
for(int i=1;i<=n;i++)
{
int ll;
scanf("%d",&ll);
add(i,ll);
}
char l[20]={0};
int a,b;
cout<<"Case "<<test<<":"<<endl;
while(scanf("%s",l))
{
if(l[0]=='E')break;
scanf("%d%d",&a,&b);
if(l[0]=='Q')
{
cout<<sum(a,b)<<endl;
}
if(l[0]=='A')
{
add(a,b);
}
if(l[0]=='S')
{
add(a,-b);
}
}
}
}
后注:
这道题卡时间卡的比较严重,cin变成scanf就从超时变成了ac。不过也可能是因为我代码效率不高的原因。在想树状数组的时候,感觉一开始把已知的a数组创建成tree的过程还可以更快,虽然时间复杂度也是O(logn),但是总的操作次数确实会变少,有时间要想一下这个思路的代码实现,然后在下一篇博客或者下次培训的时候把bulid函数思路讲出来吧。