四道树状数组模版题

概念与实现就(lande)不写了,反正一大堆

#532. 数星星

(严格来说其实不是模版题,但由于实际编码接近模版题,当作模版题来说)

题目描述

天文学家经常要检查星星的地图,每个星星用平面上的一个点来表示,每个星星都有坐标。我们定义一个星星的“级别”为给定的星星中不高于它并且不在它右边的星星的数目。天文学家想知道每个星星的“级别”。

                            5
                          *
                        4
                      *
                    1       2   3
                  *       *   *

例如上图,5号星的“级别”是3(1,2,4这三个星星),2号星和4号星的“级别”为1。

给你一个地图,你的任务是算出每个星星的“级别”。

(这图要横着看)

输入格式

输入的第一行是星星的数目N(1<=N<=60000),接下来的N行描述星星的坐标(每一行是用一个空格隔开的两个整数X,Y,0<=X,Y<=32000)。

星星的位置互不相同。星星的描述按照Y值递增的顺序列出,Y值相同的星星按照X值递增的顺序列出。

由于说到(星星的描述按照Y值递增的顺序列出,Y值相同的星星按照X值递增的顺序列出。),就可以得出结论:每输入一次x,输出x位置的前缀和,再将x加入树状数组(这里的先后顺序可以保证不将自己算进答案中),可以得到答案:

以4为例,因为在之前前缀和已经计算了比4的y值小的答案(Y值递增),又因为之前前缀和已经计算了比4的x值小的答案(Y值相同,X值递增),所以正看时getsum(x)是4的左边、正下方与左下方的所有星星个数。

所以实现的是一个最基础的树状数组:

操作:

1.单点修改

2.查询前缀和

int add(int x)
{
	for (;x<=50000;x+=lowbit(x))
	 t[x]++;
}
int getsum(int x)
{
	int ans=0;
	for (;x;x-=lowbit(x))
	 ans+=t[x];
	return ans;
}

#531. 树状数组

操作:

1.单点修改

2.查询区间和

这个没什么好说的,就是输出稍作变动:

printf("%d\n",sum(y)-sum(x-1));

这个很好理解:

一数列a[1]-a[5]:1 2 8 6 30

前缀和b[1]-b[5]:1 3 11 17 47

如果要查询3-5的区间和:

a[3]+a[4]+a[5]=a[1]+a[2]+a[3]+a[4]+a[5]-a[1]-a[2]

                       =b[5]-b[2](这个总看得懂)

                       =b[5]-b[3-1]

所以……没有所以了吧

#533. 区间修改单点查询

操作:

1.区间修改

2.单点查询


区间修改要用到差分思想:

add(x,k);
add(y+1,-k);

如果x=2 y=5 k=3

在一个长度为6数值为0的数列中:

修改后为0 3 0 0 -3

计算前缀和:0 3 3 3 0

从x的位置开始计算+k,在遇到y+1时恢复(+k-k=0)

单点查询也就是长度为1的区间查询,不再赘述

#534. 打鼹鼠

操作:

1.单点修改

2.查询平面和

这波直接上代码:

void add(int x,int y,int k)
{
	for (;x<=n;x+=lowbit(x))
	 {
	 	int j=y;
	 	for (;j<=n;j+=lowbit(j))
	 	 t[x][j]+=k;
	 }
	return;
}//在二维平面内单点修改,相信还是看得懂的
int getsum(int x,int y)
{
	int ans=0;
	for (;x;x-=lowbit(x))
	 {
	 	int j=y;
	 	for (;j;j-=lowbit(j))
	 	 ans+=t[x][j];
	 }
	return ans;
}//在二维平面内查询二维前缀和,相信也还是看得懂的
由于查询的是二维前缀和,还是要处理一下数据的:
printf("%d\n",getsum(x2,y2)+getsum(x1-1,y1-1)-getsum(x2,y1-1)-getsum(x1-1,y2));
前缀和处理成平面和的方法与处理成区间和的方法大同小异,就不再说了

猜你喜欢

转载自blog.csdn.net/fsl123fsl/article/details/79975059
今日推荐