上一篇说了线段树的应用,有一类题目不仅可以用线段树做还可以用树状数组做,一些卡时间的线段树过不了,树状数组可以过树状数组不管是在时间上还是空间上都比线段树更优(但是仅限于在某些方面比较优化,求最值问题树状数组解决不了),但是思想有点难理解,不理解就多看几天,相信功夫不负有心人。
树状数组关键点lowbit自定义函数(求的是把x的二进制的最后一个一是多少)(它的原理其他博客讲得很清楚,自行搜索)
int lowbit(int x)
{
return x&-x;
}
单点修改区间查询(以士兵杀敌二为例http://nyoj.top/problem/116)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int c[1000010];
int n,m;
int lowbit(int x)
{
return x&-x;
}
void add(int a,int i)
{
while(i<=n)
{
c[i]+=a;
i+=lowbit(i);
}
}
int get_sum(int i)
{
int sum=0;
while(i)
{
sum+=c[i];
i-=lowbit(i);
}
return sum;
}
int main()
{
int a;
scanf("%d%d",&n,&m);
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
add(a,i);
}
while(m--)
{
char s[10];
int x,y;
scanf("%s%d%d",s,&x,&y);
if(strcmp(s,"QUERY")==0)
printf("%d\n",get_sum(y)-get_sum(x-1));
else
add(y,x);
}
return 0;
}
区间修改单点查询(以士兵杀敌四为例http://nyoj.top/problem/123)
#include<stdio.h>
#include<string.h>
int a[1000010];
int t,m;
int lowbit(int x)
{
return x&-x;
}
void add(int x,int y)
{
while(x<=m)
{
a[x]+=y;
x+=lowbit(x);
}
}
int query(int x)
{
int sum=0;
while(x)
{
sum+=a[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
char b[10];
int c,d,e;
scanf("%d%d",&t,&m);
while(t--)
{
scanf("%s",b);
if(b[0]=='A')
{
scanf("%d%d%d",&c,&d,&e);
add(c,e);
add(d+1,-e);//修改的时候只修改了修改区间的第一个数和最后一个后面那个数,关键点
}
else
{
int sum=0;
scanf("%d",&c);
sum=query(c);
printf("%d\n",sum);
}
}
return 0;
}
对于士兵杀敌五来说,用线段树和树状数组都不可以,卡时间,这时候可以考虑下思路问题,这里不再说了。