在 UNR 上看到这样一道题,当时想起来就是大视野原题,发现本身居然没过,就刷了一波。c++
对于一个区间集合 \(\{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; }