Luogu P1868 饥饿的奶牛

( ext{题目链接})

(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}(mlog m + nlog 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
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/do-while-true/p/13822053.html