在 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; }