Window Area_usaco 5.3

52 篇文章 0 订阅

Description


你刚刚接手一项窗体界面工程。窗体界面还算简单,而且幸运的是,你不必显示实际的窗体。有 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 的范围内。

Input


输入文件包含给你的解释程序的一系列命令,每行一个。当输入文件结束时,停止程序。

Output


只对于 s() 命令进行输出。当然,输入文件可能有许多 s() 命令(不超过500次),所以输出文件应该是一个百分比的序列,每行一个,百分比是窗体可见部分的百分比。百分比应该四舍五入到三位小数。

Analysis


一种新的方法,学习一下
对于窗口我们开一个队列,每次置顶或置底就放在队头和队尾,对于所有的查询我们用dfs做
每次让指定的矩形上浮,遇到位于上方且相交的矩形就破碎分割成小矩形继续上浮,最后统计剩下的面积

Code


/*
ID:wjp13241
PROG:window
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <stack>
#include <queue>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define dfo(i,a,b) for (int i=a;i>=b;i--)
#define fil(x,t) memset(x,t,sizeof(x))
#define STP system("pause")
#define min(x,y) x<y?x:y
#define max(x,y) x>y?x:y
#define ld long double
#define ll long long
#define INF 0x3f3f3f3f
#define EPS 1e-4
#define N 201
#define E N*N+1
using namespace std;
struct window{int u,d,l,r;char n;}p[E];
int area=0;
void swap(window &a,window &b){window tmp=a;a=b;b=tmp;}
void cal(int now,int u,int d,int l,int r,int cnt)
{
    while (now<=cnt&&(p[now].d<=u||p[now].u>=d||p[now].l>=r||p[now].r<=l))
        now++;
    if (now>cnt)
    {
        area+=(d-u)*(r-l);
        return;
    }
    if (p[now].u>u)
    {
        cal(now+1,u,p[now].u,l,r,cnt);
        u=p[now].u;
    }
    if (p[now].d<d)
    {
        cal(now+1,p[now].d,d,l,r,cnt);
        d=p[now].d;
    }
    if (p[now].l>l)
    {
        cal(now+1,u,d,l,p[now].l,cnt);
        l=p[now].l;
    }
    if (p[now].r<r)
    {
        cal(now+1,u,d,p[now].r,r,cnt);
        r=p[now].r;
    }
}
int main()
{
    char opt;
    int cnt=0;
    while (~scanf("%c",&opt))
    {
        if (opt=='w')
        {
            int a,b,c,d;
            char n;
            scanf("%*c%c%*c%d%*c%d%*c%d%*c%d%*c",&n,&a,&b,&c,&d);
            p[++cnt]=(window){min(a,c),max(a,c),min(b,d),max(b,d),n};
        }
        if (opt=='t')
        {
            char n;
            scanf("%*c%c%*c",&n);
            fo(i,1,cnt)
                if (p[i].n==n)
                {
                    fo(j,i+1,cnt)
                        swap(p[j],p[j-1]);
                    break;
                }
        }
        if (opt=='b')
        {
            char n;
            scanf("%*c%c%*c",&n);
            dfo(i,cnt,1)
                if (p[i].n==n)
                {
                    dfo(j,i-1,1)
                        swap(p[j],p[j+1]);
                    break;
                }
        }
        if (opt=='d')
        {
            char n;
            scanf("%*c%c%*c",&n);
            fo(i,1,cnt)
                if (p[i].n==n)
                {
                    fo(j,i+1,cnt)
                        swap(p[j],p[j-1]);
                    cnt--;
                }
        }
        if (opt=='s')
        {
            char n;
            scanf("%*c%c%*c",&n);
            double ans=0;
            area=0;
            fo(i,1,cnt)
                if (p[i].n==n)
                {
                    cal(i+1,p[i].u,p[i].d,p[i].l,p[i].r,cnt);
                    ans=area/(1.0*(p[i].d-p[i].u)*(p[i].r-p[i].l))*100.0;
                    break;
                }
            printf("%.3f\n",ans);
        }
        getchar();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值