【51NOD1562】玻璃切割

题面

现在有一块玻璃,是长方形的(w 毫米× h 毫米),现在要对他进行切割。

切割的方向有两种,横向和纵向。每一次切割之后就会有若干块玻璃被分成两块更小的玻璃。在切割之后玻璃不会被移动。

现在想知道每次切割之后面积最大的一块玻璃是多少。
2≤w,h≤200000, 1≤n≤200000

分析

这种一根根的线,放在线段树里面,害得我又以为是扫描线。

其实,是可以模拟的吧?

正难则反,倒着做,先预处理出所有线左右两边的线及距离,可顺便得到最大的纵向距离和横向距离,这就是最后一次切割后的答案。

倒着删线,每次删掉一根线只增大它附近两根线的距离,判断一下删掉这根线后最大距离是否增大。

注意别把w和h看反了。WA了好几发TAT

代码

#include<bits/stdc++.h>
using namespace std;
#define N 200020
#define ll long long
ll W,H,n,p;
char op[3];
ll ans[N],mxh,mxl;
ll rem[N],tmp[N],x[N],y[N];
struct email
{
    ll pre,nxt;
    ll len;
}h[N],l[N];
int main()
{
    scanf("%d%d%d",&W,&H,&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%s%d",op,&tmp[i]);
        if(op[0]=='H')y[tmp[i]]=1,rem[i]=1;
        else    x[tmp[i]]=1;
    }
    y[0]=y[H]=1;p=0;l[H].nxt=W;
    for(ll i=0;i<=H;i++)
        if(y[i])l[i].len=i-p,l[i].pre=p,l[p].nxt=i,p=i,mxl=max(mxl,l[i].len);
    x[0]=x[W]=1;p=0;h[W].nxt=W;
    for(ll i=0;i<=W;i++)
        if(x[i])h[i].len=i-p,h[i].pre=p,h[p].nxt=i,p=i,mxh=max(mxh,h[i].len);
    ans[n]=mxh*mxl;
    for(ll i=n;i>=2;i--)
    {
        if(rem[i])
        {
            ll now=tmp[i];
            l[l[now].pre].nxt=l[now].nxt;l[l[now].nxt].pre=l[now].pre;
            l[l[now].nxt].len+=l[now].len;mxl=max(mxl,l[l[now].nxt].len);
        }
        else
        {
            ll now=tmp[i];
            h[h[now].pre].nxt=h[now].nxt;h[h[now].nxt].pre=h[now].pre;
            h[h[now].nxt].len+=h[now].len;mxh=max(mxh,h[h[now].nxt].len);
        }
        ans[i-1]=mxl*mxh;
    }
    for(ll i=1;i<=n;i++)printf("%lld\n",ans[i]);
    return 0;
}

又送样例

input1
2 2 1
V 1
output1
2

input2
5 15 10
H 8
H 9
V 1
H 2
H 6
H 4
H 1
V 2
H 13
V 3
output2
40
40
32
24
24
24
24
18
12
8

第一组也太黑了,浪费我五个积分TAT

posted @ 2018-10-19 14:37  WJEMail  阅读(135)  评论(0编辑  收藏  举报