1. 程式人生 > >[NOI2016]區間 - 線段樹

[NOI2016]區間 - 線段樹

pac amp += pda str esp iostream 插入 pan

將區間按照長度排序,每次將相同長度的區間插入,直到有一個點能被至少m個區間覆蓋,這個可以用線段樹維護。

這時我們就可以刪除長度小的區間直到不滿足條件。

重復做就可以了

技術分享圖片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <map>
  6 #define LL long long 
  7 
  8 using namespace std;
  9 
 10 inline LL read()
11 { 12 LL x = 0, w = 1; char ch = 0; 13 while(ch < 0 || ch > 9) { 14 if(ch == -) { 15 w = -1; 16 } 17 ch = getchar(); 18 } 19 while(ch >= 0 && ch <= 9) { 20 x = x * 10 + ch - 0; 21 ch = getchar();
22 } 23 return x * w; 24 } 25 26 const int MAXN = 5e5 + 10; 27 28 struct interval { 29 int l, r; 30 int len; 31 } inter[MAXN]; 32 33 int ans = 2e9; 34 int N, M; 35 map<int, int> m; 36 int tmp[MAXN * 2]; 37 int len; 38 int it[MAXN][3]; 39 int cnt = 0; 40 41 bool
cmp(interval a, interval b) 42 { 43 return a.len < b.len; 44 } 45 46 struct segment { 47 int maxn; 48 int lazy; 49 } seg[MAXN * 10]; 50 51 void pushdown(int x) 52 { 53 seg[x * 2].lazy += seg[x].lazy, seg[x * 2 + 1].lazy += seg[x].lazy; 54 seg[x * 2].maxn += seg[x].lazy, seg[x * 2 + 1].maxn += seg[x].lazy; 55 seg[x].lazy = 0; 56 } 57 58 void pushup(int x) 59 { 60 seg[x].maxn = max(seg[x * 2].maxn, seg[x * 2 + 1 ].maxn); 61 } 62 63 void update(int ul, int ur, int l, int r, int x, int k) 64 { 65 if(ul <= l && ur >= r) { 66 seg[x].maxn += k; 67 seg[x].lazy += k; 68 return; 69 } 70 int mid = (l + r) >> 1; 71 pushdown(x); 72 if(mid >= ul) { 73 update(ul, ur, l, mid, x * 2, k); 74 } 75 if(mid < ur) { 76 update(ul, ur, mid + 1, r, x * 2 + 1, k); 77 } 78 pushup(x); 79 return; 80 } 81 82 int main() 83 { 84 //cout<<sizeof seg / 1024 / 1024<<endl; 85 //freopen("inter.in", "r", stdin); 86 //freopen("iter.out", "w", stdout); 87 N = read(), M = read(); 88 for(int i = 1; i <= N; i++) { 89 tmp[i * 2 - 1] = inter[i].l = read(), tmp[i * 2] = inter[i].r = read(); 90 inter[i].len = inter[i].r - inter[i].l + 1; 91 } 92 sort(tmp + 1, tmp + 1 + 2 * N); 93 len = unique(tmp + 1, tmp + 1 + 2 * N) - tmp - 1; 94 //cout<<len<<endl; 95 for(int i = 1; i <= len; i++) { 96 m[tmp[i]] = i; 97 } 98 sort(inter + 1, inter + 1 + N, cmp); 99 /*for(int i = 1; i <= N; i++) { 100 cout<<m[inter[i].l]<<" "<<m[inter[i].r]<<endl; 101 } 102 cout<<endl; 103 /*for(int i = 1; i <= len; i++) { 104 cout<<tmp[i]<<" "; 105 } 106 cout<<endl;*/ 107 //return 0; 108 inter[0].len = -1, inter[N + 1].len = 2e9; 109 it[0][0] = 1e9; 110 for(int i = 1; i <= N + 1; i++) { 111 if(inter[i].len != inter[i - 1].len) { 112 it[cnt][1] = i - 1; 113 it[++cnt][0] = i; 114 it[cnt][2] = inter[i].len; 115 } 116 } 117 /*for(int i = 1; i <= cnt; i++) { 118 cout<<it[i][0]<<" "<<it[i][1]<<" "<<it[i][2]<<endl; 119 } 120 cout<<endl;*/ 121 int mi = 0, ma = 0; 122 int status = 0; 123 while(mi <= cnt && ma < cnt) { 124 while(seg[1].maxn < M && ma < cnt) { 125 ma++; 126 //cout<<ma<<endl; 127 //cout<<it[ma][0]<<" "<<it[ma][1]<<endl; 128 for(int i = it[ma][0]; i <= it[ma][1]; i++) { 129 update(m[inter[i].l], m[inter[i].r], 1, len, 1, 1); 130 } 131 } 132 //cout<<ma<<" "<<seg[1].maxn<<endl; 133 while(seg[1].maxn >= M) { 134 ans = min(ans, it[ma][2] - it[mi][2]); 135 for(int i = it[mi][0]; i <= it[mi][1]; i++) { 136 update(m[inter[i].l], m[inter[i].r], 1, len, 1, -1); 137 } 138 mi++; 139 //cout<<m[inter[219].l]<<" "<<m[inter[219].r]<<" "<<mi<<" "<<seg[1].maxn<<endl; 140 } 141 //cout<<mi<<endl; 142 } 143 if(ans == 2e9) { 144 ans = -1; 145 } 146 printf("%d\n", ans); 147 return 0; 148 }
View Code

[NOI2016]區間 - 線段樹