题解 P2745 【[USACO5.3]窗体面积Window Area】
题解by:redbag
大概思路同楼下
先离散,然后再根据顺序把该减的减掉,该标记的标记,具体见代码
/*
ID: ylx14271
PROG: window
LANG: C++
*/
#include<set>
#include<map>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
char ch;
int x,y,x1,y12;
int n;//存窗户的个数/标号
struct node
{
int x1,x2,y11,y2;
int id,deep,flag;
} a[2500];//存每个窗户的四个边界(x1:左,x2:右,y1:下,y2:上
map<char,int> a1;
int max1,min1;
int zx[2500],lx,ux[45000];
int zy[2500],ly,uy[45000];
int f[250][250];
void sum(int x)
{
memset(f,0,sizeof(f));
lx=0;ly=0;
for (int i=1;i<=n;i++)
{
if (a[i].flag==0||a[i].deep<a[x].deep) continue;//压在下面的或者不存在的不要处理
zx[++lx]=a[i].x1;zx[++lx]=a[i].x2;
zy[++ly]=a[i].y11;zy[++ly]=a[i].y2;//存坐标
}
sort(zx+1,zx+lx+1);//排序
sort(zy+1,zy+ly+1);
int t=0;
for (int i=1;i<=lx;i++)
{
//cout<<zx[i]<<" ";
if (zx[i]!=zx[i-1])
{
t++;
zx[t]=zx[i];
ux[zx[i]]=t;
}
}
lx=t;
//离散
t=0;
for (int i=1;i<=ly;i++)
{
//cout<<zy[i]<<" ";
if (zy[i]!=zy[i-1])
{
t++;
zy[t]=zy[i];
uy[zy[i]]=t;
}
}
ly=t;
//离散
for (int i=ux[a[x].x1];i<=ux[a[x].x2]-1;i++)
for (int j=uy[a[x].y11];j<=uy[a[x].y2]-1;j++)
f[i][j]=1;//窗户部分标记
for (int i=1;i<=n;i++)
if (a[i].deep>a[x].deep&&a[i].flag==1)
{
for (int j=ux[a[i].x1];j<=ux[a[i].x2]-1;j++)
for (int k=uy[a[i].y11];k<=uy[a[i].y2]-1;k++)
f[j][k]=0;
}//有其他窗户覆盖在上面的也标记
double sum1=0.0;
for (int i=1;i<lx;i++)
for (int j=1;j<ly;j++)
{
sum1+=f[i][j]*(zx[i+1]-zx[i])*(zy[j+1]-zy[j]);
}//算面积
double x1=100*(double)(sum1)/(double)((a[x].x2-a[x].x1)*(a[x].y2-a[x].y11));
printf("%.3lf\n",x1);//输出
return;
}
int main()
{
freopen("window.in","r",stdin);
freopen("window.out","w",stdout);
while (scanf("%c",&ch)!=EOF)
{
if (ch=='w')
{
scanf("(%c,%d,%d,%d,%d)",&ch,&x,&y,&x1,&y12);
n++;//存有多少个
a1[ch]=n;//ch的编号存起来
a[n].x1=min(x,x1);a[n].x2=max(x,x1);
a[n].y11=min(y,y12);a[n].y2=max(y,y12);
a[n].id=ch;a[n].flag=1;
max1++;//全部存起来
a[n].deep=max1;//存深度
} else
if (ch=='t')//置顶
{
scanf("(%c)",&ch);
a[a1[ch]].deep=++max1;
} else
if (ch=='b')//置底
{
scanf("(%c)",&ch);
a[a1[ch]].deep=--min1;
} else
if (ch=='d')//删除
{
scanf("(%c)",&ch);
a[a1[ch]].flag=0;
} else
if (ch=='s')//统计
{
scanf("(%c)",&ch);
sum(a1[ch]);
}
getchar();getchar();//洛谷有行末空格
}
return 0;
}