• 洛谷P2070 离散化区间


    洛谷P2070 离散化区间

    『题目传送门』:P2070 刷墙
    『思路1 题解原链接』

    题目:

    Farmer John已经设计了一种方法来装饰谷仓旁边的长栅栏(把栅栏认为是一根一维的线)。他把一只画刷绑在他最喜爱的奶牛Bessie身上,之后就去喝一杯冰水,而Bessie隔着栅栏来回走,当她走过某个地方,这里的一段栅栏就被刷上了涂料。

    Bessie从栅栏上的位置0开始,并且遵循着一个N次移动的次序(1 <= N <= 100,000)。例如“10 L”表示Bessie向左移动了10个单位长度,“15 R”表示Bessie向右移动了15个单位长度。现给出Bessie所有移动的列表,Farmer John想要知道哪些区域的栅栏至少涂了两层涂料(只涂一层涂料的区域可能在大雨中被洗掉)。Bessie在她的行走中最远到达距起始点1,000,000,000个单位长度。

    题目大意:给定(n)个区间([l,r])其中区间的长度(1leq l,rleq 1e^9),要求给出区间相交数大于2的区间长度。
    例如模拟给定的样例:

    6
    2 R
    6 L
    1 R
    8 L
    1 R
    2 R

    思路1 思维题:分情况考虑离散化(对区间考虑)

    说实话这个有点难弄清,需要细细的思考。

    思路:从小到达扫描区间,维护一个可能发生重叠的区间【L,R】,在当前维护的区间的右边寻找一个区间【a[i].l,a[i].r】
    使得当前的可能区间更新:
    分为两种情况:(对应到图右上角的1和2)

    1. 查询的区间的右端点是小于当前维护区间的右端点的,那么把【当前维护区间的左端点,当前查询区间的右端点】这一区间加入到重复区间长度计算中。并且试图在【当前查询区间的右端点,当前维护区间的右端点】寻找下一个可能的重复区间。
    2. 查询的区间的右端点是大于当前维护区间的右端点的,那么把【当前维护区间的左端点,当前维护区间的右端点】这一区间加入到重复区间长度计算中。并且试图在【当前维护区间的右端点,当前查询区间的右端点】寻找下一个可能的重复区间
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n;
    string dir;
    ll l, r;
    vector<pair<ll, ll>> alls;
    ll res;
    int main() {
      cin >> n;
      for (int i = 0; i < n; i++) {
        cin >> r >> dir;
        if (dir == "R")
          r = l + r;
        else
          r = l - r;
        ll tl, tr;
        tl = min(l, r), tr = max(l, r);
        alls.push_back(make_pair(tl, tr));
        l = r;
      }
      sort(alls.begin(), alls.end());
      //找它区间后面左端点小于右端点并且右端点最右边的点
      ll lft = alls[0].first;
      ll rgt = alls[0].second;
      for (int i = 1; i < n; i++) {
        if (alls[i].second > lft) {  //至少是有意义的区间(可能的区间至少是大于1的)
          //缩小左边的区间
          alls[i].first = max(alls[i].first, lft);
          //【alls[i].first,alls[i].second】
          //【lft          ,rgt           】
          if (alls[i].second > rgt) {    //比之前的右端点大全部覆盖
            res += rgt - alls[i].first;  //求公共区间
            lft = rgt;  //接下来有可能的区间是[rgt,alls[i].second]
            rgt = alls[i].second;
          } else {                                  //比之前的右端点小
            res += alls[i].second - alls[i].first;  //求公共区间
            lft = alls[i].second;  //接下来可能的区间是[alls.second,rgt]
          }
        }
      }
      cout << res << endl;
    
      return 0;
    }
    

    思路2:离散化+差分(对点考虑)

    对于一个区间【L,R】每出现一次,就相当于在a[l]+=1,a[r+1]-=1;
    那么就显而易见的,直接对区间的左右端点左修改,(m)次查询即完成了相应的修改,最后从小到大扫描所有的区间,若进入区间左端点后当前的差分值从1变为了2即开始进入到多个区间重合的区域,从2变到1即退出重合的区域。如下图

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    static int faster_iostream = []() {
      std::ios::sync_with_stdio(false);
      std::cin.tie(NULL);
      return 0;
    }();
    int n;
    string dir;
    ll l, r;
    vector<pii> point;
    ll res;
    int main() {
      cin >> n;
      for (int i = 0; i < n; i++) {
        cin >> r >> dir;
        if (dir == "R")
          r = l + r;
        else
          r = l - r;
        ll tl, tr;
        tl = min(l, r), tr = max(l, r);
        point.push_back(make_pair(tl, 1));
        point.push_back(make_pair(tr, -1));
        l = r;
      }
      sort(point.begin(), point.end());
      int old = 0;
      int sum = 0;
    
      for (int i = 0; i < point.size(); i++) {
        old = sum;
        sum += point[i].second;
        if (old == 1 && sum == 2) l = point[i].first;
        if (old == 2 && sum == 1) res += point[i].first - l;
      }
      cout << res << endl;
      return 0;
    }
    
  • 相关阅读:
    登入界面的创建
    什么是IO流 以及文件输入输出
    java 的面向对象
    Mac 终端命令大全
    jQuery 的属性
    商城管理系统
    Java IO学习第二天部分详解
    Java IO学习第一天部分详解
    用JAVA描述一个车与修车厂两个事物
    JAVA基础(数组)数组排序和查找数组中是否还有某一个数
  • 原文地址:https://www.cnblogs.com/adameta/p/12420069.html
Copyright © 2020-2023  润新知