题目描述
你刚刚接手一项窗体界面工程。窗体界面还算简单,而且幸运的是,你不必显示实际的窗体。有 5 种基本操作:
创建一个新窗体
将窗体置顶
将窗体置底
删除一个窗体
输出窗体可见部分的百分比(就是,不被其它窗体覆盖的部分)。
在输入文件中,操作以如下的格式出现。
创建一个新窗体:w(I,x,y,X,Y)
将窗体置顶: t(I)
将窗体置底: b(I)
删除一个窗体:d(I)
输出窗体可见部分的百分比:s(I)
I 是每个窗体唯一的标识符。表示符可以是 ‘a’..’z’, ‘A’..’Z’ 和 ‘0’..’9’ 中的任何一个。输入文件中没有多余的空格。
(x,y)和(X,Y)是窗体的对角。当你创建一个窗体的时候,它自动被“置顶”。你不能用已经存在的标识符来创建窗体,但是你 可以删除一个窗体后再用已删除窗体的标识符来创建窗体。坐标用正整数来表示,并且所有的窗体面积都不为 0(x <> X 且 y <> Y)。x 坐标和 y 坐标在 1 —— 32767 的范围内。
输入格式
输入文件包含给你的解释程序的一系列命令,每行一个。当输入文件结束时,停止程序。
输出格式
只对于 s() 命令进行输出。当然,输入文件可能有许多 s() 命令,所以输出文件应该是一个百分比的序列,每行一个,百分比是窗体可见部分的百分比。百分比应该四舍五入到三位小数。
样例数据
样例输入
w(a,10,132,20,12)
w(b,8,76,124,15)
s(a)
样例输出
49.167
说明
插入操作不超过150
总操作次数不超过1000
题目分析
这应该算是usaco史上最为恶心的调试题了吧(当然素数方阵更厉害)
对于每一个窗体看做一个矩形
维护一个队列
新加的窗体加入队尾
如果要置顶一个窗体,将他从队列中转到队尾
如果要置底一个窗体,将他从队列中转到队首
如果删除一个窗体,将他从队列中删除
以上操作均不用加入切割
如果查询,那么将队列中所有窗体顺序进行切割,统计面积
查询完毕后清空矩形切割中的矩形
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
struct Square {
double x1,x2,y1,y2;
char uuid;
Square() {}
Square(double lx,double ly,double rx,double ry,char color):x1(lx),y1(ly),x2(rx),y2(ry),uuid(color) {}
};
struct Cut_Square {
Square a[100005];
int sum;
int init() {
sum=0;
}
bool if_intersect(Square a,Square b) {
if(a.x1>=b.x2||a.y1>=b.y2||a.x2<=b.x1||a.y2<=b.y1)return false;
else return true;
}
void add(double x1,double y1,double x2,double y2,char uuid) {
a[++sum]=Square(x1,y1,x2,y2,uuid);
}
void del(int index) {
a[index]=a[sum];
sum--;
}
double Xway_cut(int index,double x1,double y1,double x2,double y2) { //返回交集
double k1=max(x1,a[index].x1);
double k2=min(x2,a[index].x2);
if(a[index].x1<k1)add(a[index].x1,a[index].y1,k1,a[index].y2,a[index].uuid);
if(k2<a[index].x2)add(k2,a[index].y1,a[index].x2,a[index].y2,a[index].uuid);
return Yway_cut(index,k1,y1,k2,y2);
}
double Yway_cut(int index,double x1,double y1,double x2,double y2) {
double k1=max(y1,a[index].y1);
double k2=min(y2,a[index].y2);
if(a[index].y1<k1)add(x1,a[index].y1,x2,k1,a[index].uuid);
if(k2<a[index].y2)add(x1,k2,x2,a[index].y2,a[index].uuid);
return (x2-x1)*(k2-k1);
}
};
struct QueNode {
char uuid;
int x1,y1,x2,y2;
QueNode() {}
QueNode(char u,int lx,int ly,int rx,int ry):uuid(u),x1(lx),y1(ly),x2(rx),y2(ry) {}
} Q[500005];
Cut_Square s;
int Right=0;
int main() {
char order,uuid;
while(scanf("%c",&order)!=EOF) {
if(order=='w') { //加入
int x1,y1,x2,y2;
scanf("(%c,%d,%d,%d,%d)",&uuid,&x1,&y1,&x2,&y2);
int tx1=x1,ty1=y1,tx2=x2,ty2=y2;
x1=min(tx1,tx2);
y1=min(ty1,ty2);
x2=max(tx1,tx2);
y2=max(ty1,ty2);
Q[++Right]=QueNode(uuid,x1,y1,x2,y2); //窗体入队
} else if(order=='t') { //置顶
int pos;
scanf("(%c)",&uuid);
for(int i=1; i<=Right; i++) //移动队列,将指定窗口放到队尾
if(Q[i].uuid==uuid) {
pos=i;
break;
}
QueNode Now=Q[pos];
for(int i=pos; i<Right; i++)Q[i]=Q[i+1];
Q[Right]=Now;
} else if(order=='b') { //置底
int pos;
scanf("(%c)",&uuid);
for(int i=1; i<=Right; i++) //移动队列,将指定窗口放到队首
if(Q[i].uuid==uuid) {
pos=i;
break;
}
QueNode Now=Q[pos];
for(int i=pos-1; i>=1; i--)Q[i+1]=Q[i];
Q[1]=Now;
} else if(order=='d') { //删除
int pos;
scanf("(%c)",&uuid);
for(int i=1; i<=Right; i++)
if(Q[i].uuid==uuid) {
pos=i;
break;
}
for(int i=pos; i<Right; i++)Q[i]=Q[i+1];
Right--;
} else if(order=='s') { //询问
int pos;
double sum=0;
scanf("(%c)",&uuid);
for(int i=1; i<=Right; i++)
if(Q[i].uuid==uuid) {
pos=i;
break;
}
for(int i=1; i<=Right; i++) { //依次添加窗体
Square b=Square(Q[i].x1,Q[i].y1,Q[i].x2,Q[i].y2,Q[i].uuid);
for(int j=1; j<=s.sum; j++) {
if(!s.if_intersect(s.a[j],b))continue; //不相交
s.Xway_cut(j,b.x1,b.y1,b.x2,b.y2);
s.del(j);
j--; //删除完矩形移动了最后一个矩形,若j不-1可能导致原矩形未切割
}
s.add(b.x1,b.y1,b.x2,b.y2,b.uuid);
}
for(int i=1; i<=s.sum; i++)
if(s.a[i].uuid==uuid)sum+=(s.a[i].x2-s.a[i].x1)*(s.a[i].y2-s.a[i].y1);
printf("%0.3lf\n",sum*100/((Q[pos].x2-Q[pos].x1)*(Q[pos].y2-Q[pos].y1)));
s.init(); //清空矩阵切割数组
}
}
return 0;
}