[BZOJ2687]交與並

在 UNR 上看到這樣一道題,當時想起來就是大視野原題,發現本身居然沒過,就刷了一波。c++

[BZOJ2687]交與並

試題描述

對於一個區間集合 \(\{A_1,A_2,\cdots,A_K\}(K>1, \forall i \ne j, A_i \ne A_j)\),咱們定義其權值 \(W=|A_1 \cup A_2 \cup \cdots \cup A_K| \cdot |A_1 \cap A_2 \cap \cdots \cap A_K|\) 固然,若是這些區間沒有交集則權值爲 \(0\)git

輸入

給你 \(N\) 個(\(1<N \le 10^6\))各不相同的區間,請你從中找出若干個區間使其權值最大。spa

第一行 \(N\),接下來\(N\)\(l\ r(1 \le l<r \le 10^6)\)code

輸出

最大權值。排序

輸入示例

4
1 6
4 8
2 7
3 5

輸出示例

24

數據規模及約定

見「輸入get

題解

顯然只有兩個區間有意義。由於首先能夠把被包含的區間去掉,而後按照左端點排序,那麼答案等於我選擇的全部區間中最靠左的和最靠右的答案。it

假設兩個區間 \(i\)\(j\)(假設 \(j\)\(i\) 左,且兩區間有交),答案就是 \((r_i - l_j)(r_j - l_i) = r_i r_j - l_i r_i - l_j r_j + l_i l_j\),讀者不妨本身證實這個 \(j \rightarrow i\) 隨着 \(i\) 往右,最優的 \(j\) 知足決策單調性。class

#include <bits/stdc++.h>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 1000010
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define LL long long

int n, N;
pii _lr[maxn], lr[maxn];

LL calc(pii a, pii b) { return (LL)(max(a.y, b.y) - min(a.x, b.x)) * (min(a.y, b.y) - max(a.x, b.x)); }
const bool cmp(const pii &a, const pii &b) { return a.x != b.x ? a.x < b.x : a.y > b.y; }
const bool wrap(const pii &a, const pii &b) { return (a.x <= b.x && b.y < a.y) || (a.x < b.x && b.y <= a.y); }

struct Info {
    int l, r, p;
    Info(int _1 = 0, int _2 = 0, int _3 = 0): l(_1), r(_2), p(_3) {}
} S[maxn];
int hd, top;
LL ans;

int main() {
    n = read();
    rep(i, 1, n) _lr[i].x = read(), _lr[i].y = read();
    
    sort(_lr + 1, _lr + n + 1, cmp);
    lr[++N] = _lr[1];
    rep(i, 2, n) if(_lr[i].y > lr[N].y) lr[++N] = _lr[i]; else ans = max(ans, calc(lr[N], _lr[i]));
    S[hd = top = 1] = Info(2, N, 1);
    rep(i, 2, N) {
        while(hd < top && i > S[hd].r) hd++;
        ans = max(ans, calc(lr[S[hd].p], lr[i]));
        while(top > hd && calc(lr[i], lr[S[top].l]) >= calc(lr[S[top].p], lr[S[top].l])) top--;
        int l = i + 1, r = N;
        while(l < r) {
            int mid = l + r >> 1;
            if(calc(lr[S[top].p], lr[mid]) > calc(lr[i], lr[mid])) l = mid + 1; else r = mid;
        }
        if(calc(lr[S[top].p], lr[l]) > calc(lr[i], lr[l])) continue;
        S[top+1] = Info(l, N, i);
        S[top].r = l - 1; ++top;
    }
    
    printf("%lld\n", ans);
    
    return 0;
}
相關文章
相關標籤/搜索