zoukankan      html  css  js  c++  java
  • [NOI2016]区间(尺取法+线段树)

    洛谷

    Main Points

    (n) 个区间,取 (m) 个,使他们有公共区域(交集),定义一个区间权值为 (r[i]-l[i]),求如何选 (m) 个满足条件区间使得其中权值最大的减去权值最小的差最小。

    Foreword

    我没学过什么尺取所以姑且就叫这个双指针了qwq。

    Analysis

    下文中区间的【权值】均指 (r-l),【满足条件】指全局中被区间覆盖次数最多的点覆盖的次数刚好为 (m)

    先解释一下为什么这样就满足条件了,如果 ([i,j]) 这一段的区间满足条件,然后就可以拿 (i,j) 来更新答案。但是有可能 (i,j) 并不是都在符合要求的区间集合里,但是这样一个满足要求的区间集合的最小最大值一定在 ([i,j]) 内,一定比拿 (i,j) 来更新答案更优,所以这肯定会被更优的解覆盖掉。

    最后的答案一定是两个区间相减,那我们不妨枚举第一个区间,然后找到最小的第二个区间。这就让我们想到如果给所有区间按权值排序,然后就可以很容易的枚举第一第二个区间了(枚举第一个区间,然后往后找到第一个满足条件的)。可是这样做的话复杂度就是 (O(n^2log{n})) 的了。考虑优化。如果枚举一段区间 ([i,j]) 不是满足条件的,则 ([i+1,j]) 也一定不满足条件,([i,j-1]) 也一定不满足条件。所以对于第一个位置往后推时第二个位置就不用重新找了,直接继续往后推就好了。这样时间复杂度就降为 (O(nlog{n}))。至于维护用离散化+线段树就好了(就是个板子了)。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    struct segment{
    	int mx, add;
    }tr[1000005 << 2];
    struct node{
    	int l, r, len;
    	friend bool operator < (node a, node b) { return a.len < b.len; }
    }p[1000005];
    int n, m, top, now, ans = 0x3f3f3f3f, tmp[1000005];
    void push_down(int cur) {
    	if (tr[cur].add) {
    		tr[cur << 1].mx += tr[cur].add; tr[cur << 1].add += tr[cur].add;
    		tr[cur << 1 | 1].mx += tr[cur].add; tr[cur << 1 | 1].add += tr[cur].add;
    		tr[cur].add = 0;
    	}
    }
    void push_up(int cur) { tr[cur].mx = max(tr[cur << 1].mx, tr[cur << 1 | 1].mx); }
    void change(int cur, int l, int r, int x, int y, int v) {
    	if (l > y || r < x) return;
    	if (x <= l && r <= y) {
    		tr[cur].mx += v, tr[cur].add += v;
    		return;
    	}
    	push_down(cur);
    	int mid = (l + r) >> 1;
    	change(cur << 1, l, mid, x, y, v); change(cur << 1 | 1, mid + 1, r, x, y, v);
    	push_up(cur);
    }
    int main() {
    	freopen("interval.in", "r", stdin); freopen("interval.out", "w", stdout);
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%d%d", &p[i].l, &p[i].r), p[i].len = p[i].r - p[i].l, tmp[++top] = p[i].l, tmp[++top] = p[i].r;
    	sort(tmp + 1, tmp + 1 + top);
    	top = unique(tmp + 1, tmp + 1 + top) - tmp - 1;
    	for (int i = 1; i <= n; i++) p[i].l = lower_bound(tmp + 1, tmp + 1 + top, p[i].l) - tmp, p[i].r = lower_bound(tmp + 1, tmp + 1 + top, p[i].r) - tmp;
    	sort(p + 1, p + 1 + n);
    	for (int i = 1, j = 0; i <= n; i++) {
    		while (j < n && tr[1].mx < m) j++, change(1, 1, top, p[j].l, p[j].r, 1);
    		if (tr[1].mx == m) ans = min(ans, p[j].len - p[i].len);
    		change(1, 1, top, p[i].l, p[i].r, -1);
    	}
    	if (ans < 0x3f3f3f3f) printf("%d", ans);
    	else puts("-1");
    	return 0;
    }
    

    编辑

  • 相关阅读:
    【Elasticsearch 技术分享】—— ES 常用名词及结构
    【Elasticsearch 技术分享】—— Elasticsearch ?倒排索引?这都是什么?
    除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
    小伙伴想写个 IDEA 插件么?这些 API 了解一下!
    部署Microsoft.ReportViewe
    关于TFS强制undo他人check out
    几段查看数据库表占用硬盘空间的tsql
    How to perform validation on sumbit only
    TFS 2012 Disable Multiple Check-out
    在Chrome Console中加载jQuery
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14081028.html
Copyright © 2011-2022 走看看