【问题描述】
塞克斯斯是六兄弟中的老六,他喜欢老大福斯特,他希望福斯特
高兴。所以他要帮福斯特写作业。作业如下:
给 n 个正方形,正方形有两种:
A 型:平行于坐标轴,中心位于(x,y),边长为偶数 a;
B 型:和坐标轴成 45 度夹角,中心位于(x,y),对角线长为偶数 d。
求这些正方形覆盖的面积总大小。
【输入格式】
第一行一个整数 n。
接下来 n 行每行描述一个正方形,共有一个字符和三个整数。如
果字符为 A 表示是 A 型正方形,接下来输入 x,y 和 a。如果字符为 B
表示是 B 型正方形,接下来输入 x,y 和 d。
【输出格式】
一行一个实数表示答案,保留 2 位小数。
【样例输入】
8
A -7 10 4
B 3 10 8
A -6 6 6
A -2 5 8
B 3 -1 8
B -7 -4 8
A 3 9 2
B 8 6 6
【样例输出】
205.50
【样例解释】
【子任务】
数据保证|x|,|y|,a,d≤1000,且 a 和 d 一定为正偶数。
数据分为三个子任务。
子任务一:20 分,保证 n≤1000。
子任务二:30 分,保证 n≤200000,只有 A 型正方形。
子任务三:50 分,保证 n≤200000。
【正解】
因为坐标范围很小,所以就想能不能枚举格子统计面积
我们用点的坐标包括上它右上角的格子
对于A型矩形(正放的矩形),前缀和维护每个格子上被多少个矩形覆盖。所以对于每个矩形,在矩形的左下角的格子权值加一,矩形的左上角的上面一个格子和矩形的右下角的右边一个格子的权值各减一,矩形的右上角的右上角格子的权值加一。最后两个循环以前缀和的方式扫描过去,每个格子上的权值就是它被多少个矩形覆盖
对于B型矩形(斜放的矩形),一样用前缀和,只不过用另一个数组记录。并且我们把坐标系也斜过去,把斜过去之后的一单位长度定位原坐标系的\(\sqrt2\)长度,那么我们就发现原坐标系里的\((x,y)\)在新坐标系里的坐标是\((x+y,x-y)\)(根据点到直线的距离公式直接求)。
最后统一扫描的时候,先扫描B的前缀和,再在扫描A的前缀和的时候统计答案。我们把每个格子拆成四个三角形。如果这个格子在A的前缀和中已经被覆盖过了,那么\(ans\)直接加4。否则找它斜过去后对应的B的前缀和中的四个格子,有多少格子被覆盖,那么\(ans\)加多少值
最后\(ans\)除4
(注意,因为B的坐标系的单位长度小,所以它的整个大小是A的坐标系的两倍)
#include<bits/stdc++.h>
#define ll long long
const int Abs=1500+10,MAXN=Abs<<1;
int s1[MAXN][MAXN],s2[MAXN<<1][MAXN<<1],n;
double ans;
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
freopen("skss.in","r",stdin);
freopen("skss.out","w",stdout);
read(n);
for(register int i=1;i<=n;++i)
{
char opt;
std::cin>>opt;
if(opt=='A')
{
int x,y,a;
read(x);read(y);read(a);
x+=Abs,y+=Abs;
s1[x-(a>>1)][y-(a>>1)]++;
s1[x-(a>>1)][y+(a>>1)]--;
s1[x+(a>>1)][y-(a>>1)]--;
s1[x+(a>>1)][y+(a>>1)]++;
}
if(opt=='B')
{
int x,y,d;
read(x);read(y);read(d);
int nx=x+y+MAXN,ny=x-y+MAXN;
s2[nx-(d>>1)][ny-(d>>1)]++;
s2[nx-(d>>1)][ny+(d>>1)]--;
s2[nx+(d>>1)][ny-(d>>1)]--;
s2[nx+(d>>1)][ny+(d>>1)]++;
}
}
for(register int i=1;i<(MAXN<<1);++i)
for(register int j=1;j<(MAXN<<1);++j)s2[i][j]+=s2[i-1][j]+s2[i][j-1]-s2[i-1][j-1];
for(register int i=1;i<MAXN;++i)
for(register int j=1;j<MAXN;++j)
{
s1[i][j]+=s1[i-1][j]+s1[i][j-1]-s1[i-1][j-1];
if(s1[i][j])
{
ans+=4.0;
continue;
}
int nx=i+j,ny=i-j+MAXN;
if(s2[nx][ny])ans++;
if(s2[nx+1][ny])ans++;
if(s2[nx][ny-1])ans++;
if(s2[nx+1][ny-1])ans++;
}
ans/=4.0;
printf("%.2f\n",ans);
return 0;
}