• BZOJ2687 交与并/BZOJ2369 区间【决策单调性优化DP】【分治】


    Description

    对于一个区间集合
    {A1,A2……Ak}(K>1,Ai不等于Aj(i不等于J),定义其权值
    S=|A1∪A2∪……AK|*|A1∩A2……∩Ak|
    即它们的交区间的长度乘上它们并区间的长度。
    显然,如果这些区间没有交集则权值为0。

    Your Task

    给定你若干互不相等的区间,选出若干区间使其权值最大。

    Input

    第一行n表示区间的个数
    接下来n行每行两个整数l r描述一个区间[l,r]

    Output

    在一行中输出最大权值

    Sample Input

    4
    1 6
    4 8
    2 7
    3 5

    Sample Output

    24

    HINT

    样例解释
    选择[1,6]和[2,7]是最优的。
    数据约定
    100%:1<N<=106,1<=L<R<=106


    思路

    首先发现一个性质:更新答案的时候只会选择两个区间

    因为如果有三个区间,要么交集是空,要么有一个被包含,就很不优秀,所以最多选两个
    然后再按照左端点为第一关键字,右端点是第二关键字来排序
    扫一遍判断包含的情况
    并把不互相包含的最大区间选出来
    这个时候推一下打个表发现对于任意的(i<j<k<l),如果在k的时候j比i优,那么在l的时候j一定比i优
    也就是具有了决策单调性
    所以就可以进行分治了
    然后只需要枚举mid的决策点是哪一个递归进行就行了
    注意要特判mid没有决策点的情况,左右区间继承父亲区间的全部决策区间


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define for_up(a, b, c) for (int a = b; a <= c; ++a)
    #define for_down(a, b, c) for (int a = b; a >= c; --a)
    #define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1e6 + 10;
    struct Segment{
      int l, r;
    }a[N], s[N];
    int n;
    bool cmp(Segment a, Segment b) {
      if (a.l == b.l) return a.r > b.r;
      return a.l < b.l;
    }
    ll ans = 0;
    void solve(int l, int r, int pl, int pr) {
      if (l >= r) return;
      int mid = (l + r) >> 1;
      int pos = 0;ll maxv = -1;
      for_up(i, pl, min(mid - 1, pr)) {
        if (s[i].r < s[mid].l) continue;
        ll val = 1ll * (s[mid].r - s[i].l) * (s[i].r - s[mid].l);
        if (val > maxv) maxv = val, pos = i;
      }
      ans = max(ans, maxv);
      if (pos) {
        solve(l, mid, pl, pos);
        solve(mid + 1, r, pos, pr);
      } else {
        solve(l, mid, pl, pr);
        solve(mid + 1, r, pl, pr);
      }
    }
    int main() {
      Read(n);
      for_up(i, 1, n) Read(a[i].l), Read(a[i].r);
      sort(a + 1, a + n + 1, cmp);
      int tot = 0, maxr = -1, pos = 0;
      for_up(i, 1, n) {
        if (a[i].r > maxr) {
          s[++tot] = a[i];
          maxr = a[i].r;
          pos = i;
        } else {
          ans = max(ans, 1ll * (a[i].r - a[i].l) * (a[pos].r - a[pos].l));
        } 
      }
      n = tot;
      solve(1, n, 1, n);
      Write(ans);
      return 0;
    }
    
  • 相关阅读:
    CreateDIBSection函数
    rand()和srand()GetTickCount函数用法
    PRIMARY LANGUAGE ID not a number
    videojs 动态加载视频
    [记录] nicescroll 在bootstrap tabs中工作
    [记录] js判断数组key是否存在
    li 水平排列并自动填满 ul
    [Laravel] 获取执行的Sql
    [Laravel]配置路由小记
    昨天冲动的搬到外面住了,oh yeah
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9733828.html
Copyright © 2020-2023  润新知