51nod-1562:玻璃切割(O(n)模拟)

题目来源:  CodeForces
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 20  难度:3级算法题
 收藏
 关注

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

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

现在想知道每次切割之后面积最大的一块玻璃是多少。

样例解释:


对于第四次切割,下面四块玻璃的面积是一样大的。都是2。


Input
单组测试数据。
第一行有三个整数 w,h,n (2≤w,h≤200000, 1≤n≤200000),表示玻璃在横向上长w 毫米,纵向上长h 毫米,接下来有n次的切割。
接下来有n行输入,每一行描述一次切割。
输入的格式是H y 或 V x。
H y表示横向切割,切割线距离下边缘y毫米(1≤y≤h-1)。
V x表示纵向切割,切割线距离左边缘x毫米(1≤x≤w-1)。
输入保证不会有两次切割是一样的。
Output
对于每一次切割,输出所有玻璃中面积最大的是多少。
Input示例
样例输入1
4 3 4
H 2
V 2
V 3
V 1
Output示例
样例输出1
8
4
4
2


http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1562

思路:倒过来处理,如果当前位置x是割线,那么

H[x].l表示该割线左面那割线的位置,

H[x].r表示该割线右面那割线的位置,

H[i].val表示该割线与左面那条割线之间的长度,

这样每次增加割线倒过来之后就相当于删除割线,

当然每次删除只要O(1)更新这条割线左右两边割线的值就好,每次答案就是max(H[i].val)*max(V[i].val),i∈[0,w(h)]

总复杂度:O(n)


#include<stdio.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct
{
	LL l, r;
	LL val;
}Line;
typedef struct
{
	char ch;
	LL x;
}Res;
Line H[200005], L[200005];
Res s[200005];
LL fx[200005], fy[200005], ans[200005];
int main(void)
{
	LL w, h, n, bx, by, i, now;
	scanf("%lld%lld%lld", &w, &h, &n);
	fx[0] = fx[h] = fy[0] = fy[w] = 1;
	for(i=1;i<=n;i++)
	{
		scanf(" %c%lld", &s[i].ch, &s[i].x);
		if(s[i].ch=='H')  fx[s[i].x] = 1;
		else  fy[s[i].x] = 1;
	}
	bx = by = 0;
	for(i=now=0;i<=h;i++)
	{
		if(fx[i]==1)
			H[i].l = now, H[i].val = i-now, H[now].r = i, now = i, bx = max(bx, H[i].val);
	}
	H[h].r = h;
	for(i=now=0;i<=w;i++)
	{
		if(fy[i]==1)
			L[i].l = now, L[i].val = i-now, L[now].r = i, now = i, by = max(by, L[i].val);
	}
	L[w].r = w;
	ans[n] = bx*by;
	for(i=n;i>=2;i--)
	{
		if(s[i].ch=='H')
		{
			H[H[s[i].x].r].val = H[s[i].x].val+H[H[s[i].x].r].val;
			H[H[s[i].x].l].r = H[s[i].x].r;
			H[H[s[i].x].r].l = H[s[i].x].l;
			bx = max(bx, H[H[s[i].x].r].val);
		}
		else
		{
			L[L[s[i].x].r].val = L[s[i].x].val+L[L[s[i].x].r].val;
			L[L[s[i].x].l].r = L[s[i].x].r;
			L[L[s[i].x].r].l = L[s[i].x].l;
			by = max(by, L[L[s[i].x].r].val);
		}
		ans[i-1] = bx*by;
	}
	for(i=1;i<=n;i++)
		printf("%lld\n", ans[i]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值