洛谷 P1496 火烧赤壁(离散化

P1496 火烧赤壁
世界上只有一种英雄主义,就是认清了生活的本质后依然爱他。
----罗曼罗兰

通往成功的道路上有很多挫折,这正是成功的意义所在。
----yxr
记今天下午上机退化成海淀区小学二年级水平。线性表不会,连简单的矩阵乘法也不会。
-.-
----------------------------正文--------------------------------

题意很好理解,求火烧过的长度。
简单的做法是开一个很大很大的数组,有火为1,否则为0,数有多少个1就可以了。
显然,会爆。

既然RE,数组又有大量的空间没有存东西。“压缩”一下,也就是离散化。
离散化三步走:

  1. 排序
  2. 去重,用unique函数
  3. 二分查找,用lower_bound函数

举个栗子,如果初始输入的num数组为

num[6]={1,-1,1,9,2,5}

处理后的数组为:

sum[5]={-1,1,2,5,9}
num[6]={2,1,2,5,3,4}

处理后的num数组存的不是原来的数,而是这些数经过离散化处理后在sum中的位置。
通过位置一样也可以索取这些数的数值。

从num数组获取sum中的下标从而获取数据解决问题。

关于unique和lower_bound:

        sort(num,num+length);
        length=unique(num,num+length)-num;

unique和sort用法基本一致,第一个为起始位置,最后一个为结束位置+1。返回值为最后一个元素位置+1的地址。由于返回的是容器末尾,所以如果想得到去重后的size,需要减去初始地址。

		a[i]=lower_bound(c+1,c+x,a[i])-c;

lower_bound,第一个为起始位置,第二个为结束位置+1,最后一个为要查找的元素。返回值为第一个大于等于值的地址。

对于此题,我们用一个数组flag判断是否可以加上该点与后继点的距离。num中的每一组数据对应的下标,从最左边一直标记到最右边减一。遍历一遍sum,从左加到右即可。
文字描述太过苍白。
举个栗子:

-1 1
2 9
5 11

在sum中为:

-1 1 2 5 9 11

*flag为:

1 0 1 1 1 0

从左加到右即得:2+3+4+2=11

喜闻乐见的 代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <math.h>
#include <stdlib.h>
#include <functional>
#include <string>
#include <vector>
#include <map>
#include <stack>
#include <cstdio>
#include <deque>
#include <list>
#include <queue>
#include <set>
#include <unordered_map>
#define ll long long
using namespace std;

ll n,x=1,ans=0;
ll a[90100],b[90100];
ll c[90100];
ll flag[90100];


int main(){
    cin>>n;
    ll i;
    for(i=1 ;i<=n ;i++ ){
        std::cin>>a[i];
        std::cin>>b[i];
        c[x++]=a[i];
        c[x++]=b[i];
    }
    sort(c+1,c+x);
    for(i=1;i<=n;i++){
        a[i]=lower_bound(c+1,c+x,a[i])-c;
        b[i]=lower_bound(c+1,c+x,b[i])-c-1;
        for(ll j=a[i];j<=b[i];j++) flag[j]=1;
    }
    for(i=1;i<=x;i++){
        if(flag[i])  ans+=(c[i+1]-c[i]);
    }
    cout<<ans;
}

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页