題解【bzoj4653 [NOI2016] 區間】
阿新 • • 發佈:2018-12-01
先按照長度排個序,然後依次新增區間。什麼是新增?設這個區間是\([l,r]\),新增就是把\(a_l,a_{l+1},a_{l+2},{...},a_{r}\)都加上\(1\),其中\(a_i\)表示第\(i\)個位置被幾個區間覆蓋。拿走一個區間的含義就是把它們都減\(1\)。這個過程很顯然可以用線段樹維護。
如果在新增到一個區間 \(i\) 時,有一個點被區間覆蓋了\(M\)次,那麼先更新答案,再把前面的加入過的區間一直拿直到沒有一個點被覆蓋\(M\)次。如何判斷有沒有點被覆蓋\(M\)次?因為是一個一個區間加的,所以只用維護一個\(a_i\)的最大值,看他是否\(=M\)就行了。
什麼叫再把前面的加入過的區間一直拿直到沒有一個點被覆蓋\(M\) 次?
比如你一直新增區間到第\(5\)個,此時有一個點被覆蓋了\(M\)次。這時你就將第一個區間拿出,如果此時依然有有一個點被覆蓋了\(M\)次,那麼你就拿走第二個...
這個過程就好比一個佇列,可以從後面新增區間達到一個點被覆蓋了\(M\)次;從前面彈出區間直到沒有一個點被覆蓋了\(M\)次。
差不多就是這樣,還有注意一下\(l_i,r_i \leq 10^9\),開線段樹是要離散化的。上程式碼:
#include <bits/stdc++.h> #define INF 1000000001 using namespace std; const int N = 500500; int n, m, cnt, tot, ans = INF; struct Seg { int l, r, len; bool operator < (const Seg &x) const { return len < x.len; } }a[N]; struct KEY { int d, id, se; }key[N * 2]; inline bool cmp1(KEY x, KEY y) { return x.d < y.d; } inline bool cmp2(KEY x, KEY y) { return x.id < y.id; } struct node { int left, right, Max, lazy; node *ch[2]; }pool[N * 4], *root; inline void pushup(node *r) { r->Max= max(r->ch[0]->Max, r->ch[1]->Max); } inline void pushdown(node *r) { if(!r->lazy) return ; r->Max += r->lazy; if(r->ch[0]) r->ch[0]->lazy += r->lazy; if(r->ch[1]) r->ch[1]->lazy += r->lazy; r->lazy = 0; return ; } inline void build(node *r, int left, int right) { r->left = left, r->right = right; if(left == right) return ; int mid = (left + right) >> 1; node *lson = &pool[++cnt], *rson = &pool[++cnt]; r->ch[0] = lson, r->ch[1] = rson; build(lson, left, mid), build(rson, mid + 1, right); } inline void change(node *r, int left, int right, int d) { if(r->left == left && r->right == right) { r->lazy += d; return ; } pushdown(r); if(r->ch[0]->right >= right) change(r->ch[0], left, right, d); else if(r->ch[1]->left <= left) change(r->ch[1], left, right, d); else change(r->ch[0], left, r->ch[0]->right, d), change(r->ch[1], r->ch[1]->left, right, d); pushdown(r->ch[0]), pushdown(r->ch[1]), pushup(r); } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d%d", &a[i].l, &a[i].r); a[i].len = a[i].r - a[i].l; key[++tot].d = a[i].l, key[tot].id = tot; key[++tot].d = a[i].r, key[tot].id = tot; } sort(key + 1, key + tot + 1, cmp1); key[0].d = -1; key[0].se = 0; for(int i = 1; i <= tot; i++) if(key[i].d == key[i - 1].d) key[i].se = key[i - 1].se; else key[i].se = key[i - 1].se + 1; sort(key + 1, key + tot + 1, cmp2); for(int i = 1; i <= n; i++) a[i].l = key[i * 2 - 1].se, a[i].r = key[i * 2].se; sort(a + 1, a + n + 1); build(root = &pool[0], 1, 2 * n + 1); int pos = 1; change(root, a[1].l, a[1].r, 1); if(m == 1) ans = 0; for(int i = 2; i <= n; i++) { change(root, a[i].l, a[i].r, 1); while(root->Max >= m) { change(root, a[pos].l, a[pos].r, -1); ans = min(ans, a[i].len - a[pos].len); pos++; } } if(ans == INF) ans = -1; printf("%d\n", ans); return 0; }