• 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;
    }
    
  • 相关阅读:
    spring 使用 context:property-placeholder 加载 多个 properties
    Spring自动注入Bean
    正则查询符合条件的字符串
    csv测试类。用起来,就是那么简单。每个单元格都是以逗号分隔
    eclipse 设置字体高亮
    订单生成类,个人经验总结!
    java 导出Excel 大数据量,自己经验总结!
    Oracle的数据恢复——Flashback用法汇总
    org.apache.log4j.Logger详解
    Date、String和Timestamp类型转换
  • 原文地址:https://www.cnblogs.com/do-while-true/p/13822053.html
Copyright © 2020-2023  润新知