概念与实现就(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));
前缀和处理成平面和的方法与处理成区间和的方法大同小异,就不再说了