LG8470
题意
\(n\) 次操作,每次在矩形地面上选择一个格子 \((x_i,y_i)\),在上面加上 \(z_i\) 个方块。一个立体图形的「侧面积」定义为所有方块的前后左右面不紧贴着另一个方块,则该面计入「侧面积」。求每次操作后立体图形的侧面积。
分析
最直接的想法就是每加入 \(z_i\) 个方块后,总的侧面积直接加上 \(z_i \times 4\) 即可(前后左右共四个面)。但是,如果它的四周也有方块,那么这样就是不完整的,因此我们要分类讨论。我们不妨先设 \((x_i,y_i)\) 上原有 \(a\) 个方块,周围的其中一个位置有 \(b\) 个方块(其它位置同理),现要在 \((x_i,y_i)\) 的位置加入 \(c\) 个方块。
- \(a \le b\),\(a+c \le b\)
这种情况是原来比周围的低,增加了方块之后仍然比周围的低。增加了 \(c\) 个方块后,那么两者紧贴的面积就增加了 \(c\),即侧面积减少了 \(c\)。
- \(a \le b\),\(a+c >b\)
这种情况是原来比周围的低,但加了 \(c\) 个方块后,超过了周围的高度。因此很容易得知原来的高度差 \(b-a\) 没了,然后产生了新的高度差 \((a+c)-b\),因此此时的侧面积要加上 \((a+c)-b-(b-a)\)。
- \(a > b\)
这种情况不用多说了,原来已经比周围的高,那么加上 \(c\) 个方块后也不会有方块紧贴着,所以侧面积直接加上 \(c\) 即可。
实现
由于 \(1 \le x,y \le 10^9\),普通的二维数组无法开到这么大的值域,因此我们可以用 map,map 里再开一个 map,就可以达到二维数组的效果(或者用 hash 也可以)。注意,求侧面积的变量要开 unsigned long long(极限数据 \(3 \times 10^5 \times 10^{13} \times4 = 1.2 \times 10^{19}\),会爆 long long)。
具体实现细节见代码:
#include <bits/stdc++.h>
using namespace std;
unsigned long long ans;
long long z;
int x,y;
map<int,map<int,long long> > a;
int main()
{
int n;
cin>>n;
while(n--)
{
cin>>x>>y>>z;
a[x][y]+=z;
if(a[x-1][y]>=a[x][y]) ans=ans-z;
else if(a[x][y]-z<a[x-1][y]) ans=ans-(a[x-1][y]-(a[x][y]-z))+(a[x][y]-a[x-1][y]);
else ans=ans+z;
if(a[x+1][y]>=a[x][y]) ans=ans-z;
else if(a[x][y]-z<a[x+1][y]) ans=ans-(a[x+1][y]-(a[x][y]-z))+(a[x][y]-a[x+1][y]);
else ans=ans+z;
if(a[x][y-1]>=a[x][y]) ans=ans-z;
else if(a[x][y]-z<a[x][y-1]) ans=ans-(a[x][y-1]-(a[x][y]-z))+(a[x][y]-a[x][y-1]);
else ans=ans+z;
if(a[x][y+1]>=a[x][y]) ans=ans-z;
else if(a[x][y]-z<a[x][y+1]) ans=ans-(a[x][y+1]-(a[x][y]-z))+(a[x][y]-a[x][y+1]);
else ans=ans+z;
cout<<ans<<endl;
}
}