Luogu P1868 饥饿的奶牛
\(\text{题目链接}\)
\(Solution\)
简单来说为给定多个区间,求出若干不相交区间的区间覆盖长度的最大值。
计第 \(i\) 个区间的左端点为 \(l_i\), 右端点为 \(r_i\),长度为 \(len_i=r_i-l_i+1\)。以右端点为关键字排序,就有一个非常无脑的 \(\mathcal{O}(n^2)\) 的 \(dp\):
计 \(f_i\) 为在前 \(i\) 个区间内选择并且选择第 \(i\) 个区间的最大答案,则有
\[f_i=len_i+\max\{f_j\}\ \ (j<i\&\&r_j<l_i)
\]
也就是从第 \(j\) 个区间后面接上了第 \(i\) 个区间。
用以 \(r\) 为下标的线段树优化那个 \(\max\) 即可。
计 \(m=\max\{r_i\}\),复杂度为 \(\mathcal{O}(m\log m + n\log m)\)。
\(Code\)
#include<iostream>
#include<cstdio>
#include<algorithm>
inline int Max(int x, int y) { return x > y ? x : y; }
inline int Min(int x, int y) { return x < y ? x : y; }
inline int read() {
int r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w = 1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
r = (r << 3) + (r << 1) + (ch ^ 48);
ch = getchar();
}
return w ? ~r + 1 : r;
}
const int N = 150010;
const int M = 3000010;
const int INF = 0x7fffffff;
int n, m;
int f[N];
struct Line {
int l, r, len;
}a[N];
bool cmp(Line x, Line y) {
return x.l < y.l;
}
//SGT
#define ls (tree[x].lson)
#define rs (tree[x].rson)
int trnt = 1;
struct SGT {
int l, r, sum, tag, lson, rson;
}tree[M << 2];
inline void pushup(int x) { tree[x].sum = Max(tree[ls].sum, tree[rs].sum); }
inline void pushdown(int x) {
if(tree[x].tag) {
int p = tree[x].tag; tree[x].tag = 0;
tree[ls].sum = Max(tree[ls].sum, p); tree[rs].sum = Max(tree[rs].sum, p);
tree[ls].tag = Max(tree[ls].tag, p); tree[rs].tag = Max(tree[rs].tag, p);
}
}
void build(int x, int l, int r) {
tree[x].l = l; tree[x].r = r; tree[x].sum = tree[x].tag = 0;
if(l == r) return;
int mid = (l + r) >> 1;
ls = ++trnt; rs = ++trnt;
build(ls, l, mid); build(rs, mid + 1, r);
pushup(x);
}
int query(int x, int l, int r) {
if(tree[x].l >= l && tree[x].r <= r) return tree[x].sum;
int mid = (tree[x].l + tree[x].r) >> 1, sumq = 0;
pushdown(x);
if(mid >= l) sumq = Max(sumq, query(ls, l, r));
if(mid < r) sumq = Max(sumq, query(rs, l, r));
pushup(x);
return sumq;
}
void modify(int x, int l, int r, int k) {
if(tree[x].l >= l && tree[x].r <= r) {
tree[x].sum = Max(tree[x].sum, k);
tree[x].tag = Max(tree[x].tag, k);
return ;
}
int mid = (tree[x].l + tree[x].r) >> 1;
pushdown(x);
if(mid >= l) modify(ls, l, r, k);
if(mid < r) modify(rs, l, r, k);
pushup(x);
}
#undef ls
#undef rs
int main() {
n = read();
for(int i = 1; i <= n; ++i) a[i].l = read(), a[i].r = read(), a[i].len = a[i].r - a[i].l + 1, m = Max(m, a[i].r);
std::stable_sort(a + 1 ,a + n + 1, cmp);
f[1] = a[1].len;
build(1, 1, m);
modify(1, a[1].r, a[1].r, f[1]);
for(int i = 2; i <= n; ++i) {
f[i] = a[i].len + query(1, 1, a[i].l - 1);
modify(1, a[i].r, a[i].r, f[i]);
}
int ans = 0;
for(int i = 1; i <= n; ++i) ans = Max(ans, f[i]);
printf("%d\n", ans);
return 0;
}