bzoj4653 [Noi2016]区间
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4653
【题解】
首先把区间按长度从小到大排好序。
那么取一些区间,花费为长度最大-长度最小,相当于把这个长度区间里面的区间都取了。
求是不是有一个位置被覆盖超过了m次。
那么这个用two-pointer和线段树就能实现啦!
# include <vector> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m; struct intervals { int l, r; intervals() {} intervals(int l, int r) : l(l), r(r) {} friend bool operator < (intervals a, intervals b) { return a.r-a.l < b.r-b.l; } }p[M], a[M]; vector<int> ps; namespace SGT { const int M = 4e6 + 10; int w[M], lazy[M]; # define ls (x<<1) # define rs (x<<1|1) inline void down(int x) { if(!x) return ; if(!lazy[x]) return ; w[ls] += lazy[x], lazy[ls] += lazy[x]; w[rs] += lazy[x], lazy[rs] += lazy[x]; lazy[x] = 0; } inline void change(int x, int l, int r, int L, int R, int d) { if(L <= l && r <= R) { w[x] += d; lazy[x] += d; return ; } down(x); int mid = l+r>>1; if(L <= mid) change(ls, l, mid, L, R, d); if(R > mid) change(rs, mid+1, r, L, R, d); w[x] = max(w[ls], w[rs]); } inline int get() { return w[1]; } } int main() { cin >> n >> m; for (int i=1; i<=n; ++i) scanf("%d%d", &p[i].l, &p[i].r); sort(p+1, p+n+1); for (int i=1; i<=n; ++i) ps.push_back(p[i].l), ps.push_back(p[i].r); sort(ps.begin(), ps.end()); ps.erase(unique(ps.begin(), ps.end()), ps.end()); for (int i=1; i<=n; ++i) { a[i].l = lower_bound(ps.begin(), ps.end(), p[i].l) - ps.begin() + 1; a[i].r = lower_bound(ps.begin(), ps.end(), p[i].r) - ps.begin() + 1; } int mx = ps.size(), ans = 1e9; for (int l=1, r=0; l<=n; ++l) { if(SGT::get() != m) { while(r<n) { ++r; SGT::change(1, 1, mx, a[r].l, a[r].r, 1); if(SGT::get() == m) break; } } if(SGT::get() != m) break; ans = min(ans, p[r].r - p[r].l - p[l].r + p[l].l); SGT::change(1, 1, mx, a[l].l, a[l].r, -1); } if(ans == 1e9) cout << -1; else cout << ans; return 0; }