51nod 1562 玻璃切割 (STL map+一点点的思考)

题目来源: 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维的即可。
 
 
写起来很绕,需要很强的编码能力,不过这与问题的解决办法已经无关了。
 
 
代码:
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <math.h>
#include <queue> 
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef long long ll;
#define INF 2147483647

//输入 
int w, h, n;

//mh:高度方向上每个间隔出现的次数。mh[i] = j表示间隔为i的线段有j个。 
//mv:宽度方向上每个间隔出现的次数。mv[i] = j表示间隔为i的线段有j个。
//h1: h1[i] = j表示高度方向上切割点为i的线段的长度为j。
//v1: v1[i] = j表示宽度方向上切割点为i的线段的长度为j。
map <int, int> mh, mv, h1, v1;
map <int, int>::iterator it, it1;

int main() {
    scanf("%d%d%d", &w, &h, &n);
    //初始化,长度为h的线段+1,长度为w的线段+1,以0为起点的线段长为h,以0为起点的线段长为w。 
    mh[h] = 1;
    mv[w] = 1;
    h1[0] = h;
    v1[0] = w;

    char k1;
    int k2;
    while (n--) {
        getchar();
        scanf("%c%d", &k1, &k2);

        if (k1 == 'H') {
            //找到切割点前一个点的位置和长度。 
            it = h1.lower_bound(k2); it--;
            int con = it->first;
            int len = it->second;

            //长度为len的线段-1,如果为0了就从map中删掉 
            mh[len]--;
            if (mh[len] == 0) mh.erase(len);

            //h1: h1[i] = j表示高度方向上切割点为i的线段的长度为j。
            h1[con] = k2 - con;
            h1[k2] = len - h1[con];

            //mh:高度方向上每个间隔出现的次数。mh[i] = j表示间隔为i的线段有j个。 
            mh[h1[k2]]++;
            mh[h1[con]]++;

        }
        else if (k1 == 'V') {
            it = v1.lower_bound(k2); it--;
            int con = it->first;
            int len = it->second;

            mv[len]--;
            if (mv[len] == 0) mv.erase(len);
            v1[con] = k2 - con;
            v1[k2] = len - v1[con];
            mv[v1[k2]]++;
            mv[v1[con]]++;
        }

        //map最后一个值的key最大 
        it = mh.end(); it--;
        it1 = mv.end(); it1--;
        ll p = it->first;
        ll q = it1->first;
        printf("%lld\n", p*q);
    }
    getchar(); getchar();
    return 0;
}
/*
10 10 5
H 1
H 8
H 6
H 2
H 4
*/

 

转载于:https://www.cnblogs.com/zhangjiuding/p/7855636.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值