• 【洛谷 P1712】 [NOI2016]区间 (线段树+尺取)


    题目链接
    emmm看起来好像无从下手,
    (l_i,r_i)这么大,肯定是要离散化的。
    然后我们是选(m)个区间,我们先对这些区间按长度排个序也不影响。
    排序后,设我们取的(m)个区间的编号(b_1,b_2,...,b_m)
    (b_m)确定,我们肯定是要尽量使(b_1,b_2,...,b_{m-1})尽量接近(b_m)的,这样可使代价最小。
    所以,就可以尺取了。
    定义两个指针(l,r),首先(r)指针不停右移覆盖一遍扫到的区间直到满足条件有一个点被连续覆盖(m)次,怎么判断?显然维护一棵最大值线段树就好了。
    当满足条件,就让(l)指针右移直到不满足条件,更新答案。

    #include <cstdio>
    #include <algorithm>
    using std::sort;
    #define INF 2147483647
    const int MAXN = 650010;
    int n, m, q;
    char ch;
    inline int max(int a, int b){
    	return a > b ? a : b;
    }
    inline int min(int a, int b){
    	return a > b ? b : a;
    }
    inline int read(){
    	q = 0; ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') { q = q * 10 + ch - '0'; ch = getchar(); }
    	return q;
    }
    struct Seg{
    	int l, r, len;
    	bool operator < (const Seg A) const{
    		return len < A.len;
    	}
    }s[MAXN];
    struct LSH{
    	int id, pos, val;
    	bool operator < (const LSH A) const{
    		return val < A.val;
    	}
    }p[MAXN << 1];
    int cnt, num;
    namespace SegTree{
        #define left (now << 1)
        #define right (now << 1 | 1)
    	int Max[MAXN << 2 << 1], lazy[MAXN << 2 << 1];
    	inline void pushup(int now){
    		Max[now] = max(Max[left], Max[right]);
    	}
    	inline void pushdown(int now){
    		if(lazy[now]){
    			Max[left] += lazy[now];
    			Max[right] += lazy[now];
    			lazy[left] += lazy[now];
    			lazy[right] += lazy[now];
    			lazy[now] = 0;
    		}
    	}
    	void update(int now, int l, int r, int wl, int wr, int p){
    		if(l >= wl && r <= wr){ Max[now] += p; lazy[now] += p; return; }
    		pushdown(now);
    		int mid = (l + r) >> 1;
    		if(wl <= mid) update(left, l, mid, wl, min(mid, wr), p);
    		if(wr > mid) update(right, mid + 1, r, max(mid + 1, wl), wr, p);
    		pushup(now);
    	}
    	int query(int now, int l, int r, int wl, int wr){
    		if(l >= wl && r <= wr) return Max[now];
    		int ans = 0;
    		pushdown(now);
    		int mid = (l + r) >> 1;
    		if(wl <= mid) ans = max(ans, query(left, l, mid, wl, min(mid, wr)));
    		if(wr > mid) ans = max(ans, query(right, mid + 1, r, max(mid + 1, wl), wr));
    		return ans;
    	}
    }using namespace SegTree;
    int ans = INF;
    int main(){
    	n = read(); m = read();
    	for(int i = 1; i <= n; ++i){
    		s[i].l = read(); s[i].r = read();
    		s[i].len = s[i].r - s[i].l;
    		p[++cnt].val = s[i].l; p[cnt].id = i; p[cnt].pos = 1;
    		p[++cnt].val = s[i].r; p[cnt].id = i; p[cnt].pos = 2;
    	} p[0].val = -1;
    	sort(p + 1, p + cnt + 1);
    	for(int i = 1; i <= cnt; ++i)
    		if(p[i].pos == 1)
    			if(p[i].val != p[i - 1].val)
    				s[p[i].id].l = ++num;
    			else s[p[i].id].l = num;
    		else
    			if(p[i].val != p[i - 1].val)
    				s[p[i].id].r = ++num;
    			else s[p[i].id].r = num;
    	sort(s + 1, s + n + 1);
    	int l = 1, r = 0;
    	while(r < n){
    		while(r < n && Max[1] < m){
    			++r;
    			update(1, 1, num, s[r].l, s[r].r, 1);
    		}
    		if(Max[1] < m) break;
    		int tmp;
    		while(Max[1] >= m) tmp = s[l].len, update(1, 1, num, s[l].l, s[l].r, -1), ++l;
    		ans = min(ans, s[r].len - tmp);
    	}
    	printf("%d
    ", ans == INF ? -1 : ans);
    	return 0;
    }
    
    
  • 相关阅读:
    九九乘法表
    数据汇总特殊处理-标题都在第N行
    Python库——Faker 安装及用法
    faker库 生成数据导入文件
    faker库的使用 faker是一个第三方Python包,为您生成你所需要的任何(假)数据。 安装:pip install faker
    生成随机数据:faker库
    运算符
    初识编码
    网页设计基础(二)
    网页设计基础
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/9739303.html
Copyright © 2020-2023  润新知