树状数组专题
写在前面:
自从我昨天更了之后,我机房的小伙伴就炸了(我(一种植物)!!牛啊!那树状数组和线段树又是什么关系呢?有兴趣安排一下树状数组吗?)
经过我抗拒了全身托更细胞后,我还是决定来更新,请大家多多支持!
概念:
树状数组:使用数组模拟树形结构,(为啥不建树呢?)没必要,能树状数组解决的东西,就没几个人会认真打树吧(不会吧,不会吧)。相对于线段树,它加乘操作更加为之简洁,实现更为之简单。这是无法与之比拟的,因此,我们也要认真学习树状数组。
还有基本常识: 查询和修改的时间复杂度均为 O(log(n))
空口无凭,我们不如去实战一番吧!
求和:
题目大意:
输入一个数列A1,A2….An(1<=N<=100000),在数列上进行M(1<=M<=100000)次操作,操作有以下两种:
(1) 格式为C I X,其中C为字符“C”,I和X(1<=I<=N,|X|<=10000)都是整数,表示把把a[I]改为X
(2) 格式为Q L R,其中Q为字符“Q”,L和R表示询问区间为L,R,表示询问A[L]+…+A[R]的值。
对于每个Q L R 的操作输出答案。
解题思路:
ok,完美的裸题,我们直接过来用树状数组敲一下代码。
首先,我们要引入一个新的东西:lowbit( int x ),这个东西求的是2进制数下最低位1的位置,主要用于二分。
很奇妙对吧?但…如何求出它呢?首先,我们看到 2进制数 时,就应该 0光一闪(位运算!)
code:
int lowbit(int x)
{
return x&(-x);
}
修改
疯狂加lowbit code:
void backspace(int p,int num)
{
while (p<=n)
{
c[p]+=num;
p+=change(p);
}
return;
}
查询
疯狂减lowbit code:
int question(int p)
{
int tmp=0;
while (p)
{
tmp+=c[p];
p-=change(p);
}
return tmp;
}
主程序
合并,没什么好难得,来康康!
code:
#include<bits/stdc++.h>
using namespace std;
int maxn=100010;
int n,m;int a[100010];
int c[100010];
char s[2];
int change(int p)
{
return (p&(-p));
}
void backspace(int p,int num)
{
while (p<=n)
{
c[p]+=num;
p+=change(p);
}
return;
}
int question(int p)
{
int tmp=0;
while (p)
{
tmp+=c[p];
p-=change(p);
}
return tmp;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
backspace(i,a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='C')
{
int j,k;
scanf("%d%d",&j,&k);
backspace(j,k-a[j]);
a[j]=k;
}
else
{
int l,r;
scanf("%d%d",&l,&r);
int sum=question(r)-question(l-1);
printf("%d\n",sum);
}
}
return 0;
}
星星点灯:
题目大意:
天文学家经常要检查星星的地图,每个星星用平面上的一个点来表示,每个星星都有坐标。我们定义一个星星的“级别”为给定的星星中不高于它并且不在它右边的星星的数目。天文学家想知道每个星星的“级别”。
5
*
4
*
1 2 3
* * *
例如上图,5号星的“级别”是3(1,2,4这三个星星),2号星和4号星的“级别”为1。
给你一个地图,你的任务是算出每个星星的“级别”
解题思路:
ok,完美的裸题,我们直接过来变一下,定义sum,疯狂加上c数组即可。
主程序
code:
#include<bits/stdc++.h>
#define MAX 3*1e9
#define MIN -3*le9
using namespace std;
int n,m;
int lazy[100001];
int lowbit(int x)
{
return x&(-x);
}
int question(int x)
{
int sum=0;
while(x!=0)
{
sum+=lazy[x];
x-=lowbit(x);
}
return sum;
}
void backspace(int x)
{
while(x<=32000)
{
lazy[x]++;
x+=lowbit(x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
int z=question(x+1);
printf("%d\n",z);
backspace(x+1);
}
return 0;
}
写在最后:
树状数组简洁,便利,好用,是居家AC不二之选,让我们认真学习它把!
(不敢相信,我居然日更!)