BZOJ 4653: [Noi2016]区间
4653: [Noi2016]区间
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 457 Solved: 245
[Submit][Status][Discuss]
Description
在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。
Input
第一行包含两个正整数 n,m用空格隔开,意义如上文所述。保证 1≤m≤n
接下来 n行,每行表示一个区间,包含用空格隔开的两个整数 li 和 ri 为该区间的左右端点。
N<=500000,M<=200000,0≤li≤ri≤10^9
Output
只有一行,包含一个正整数,即最小花费。
Sample Input
6 3
3 5
1 2
3 4
2 2
1 5
1 4
3 5
1 2
3 4
2 2
1 5
1 4
Sample Output
2
HINT
Source
这个题吧,就先拿每条线段的长度排序,然后枚举一下最短线段,发现最长线段只会单调变长,所以只需要知道当前维护的区间内是否有个合法的X使得X存在于区间内至少M条线段内。这个就是线段树支持区间加减,全局最值(当然要先对所有坐标离散化处理)。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 template <class T> 6 inline T Max(const T &a, const T &b) 7 { 8 return a > b ? a : b; 9 } 10 11 template <class T> 12 inline T Min(const T &a, const T &b) 13 { 14 return a < b ? a : b; 15 } 16 17 inline int nextChar(void) 18 { 19 static const int siz = 1 << 20; 20 21 static char buf[siz]; 22 static char *hd = buf + siz; 23 static char *tl = buf + siz; 24 25 if (hd == tl) 26 fread(hd = buf, 1, siz, stdin); 27 28 return int(*hd++); 29 } 30 31 inline int nextInt(void) 32 { 33 int r = 0, c = nextChar(); 34 35 for (; c < 48; c = nextChar()); 36 for (; c > 47; c = nextChar()) 37 r = r * 10 + c - '0'; 38 39 return r; 40 } 41 42 const int mxn = 500005; 43 const int mxm = 200005; 44 45 int n, m; 46 47 struct line 48 { 49 int l, r, len; 50 }L[mxn], *ln[mxn]; 51 52 inline bool cmp(line *a, line *b) 53 { 54 return a->len < b->len; 55 } 56 57 int map[mxn << 1], tot; 58 59 inline int find(int k) 60 { 61 int lt = 1, rt = tot, mid, ans; 62 63 while (lt <= rt) 64 { 65 mid = (lt + rt) >> 1; 66 67 if (map[mid] <= k) 68 lt = mid + 1, ans = mid; 69 else 70 rt = mid - 1; 71 } 72 73 return ans; 74 } 75 76 const int siz = 4000005; 77 78 int tag[siz]; 79 int max[siz]; 80 81 void add(int t, int l, int r, int x, int y, int v) 82 { 83 if (l == x && r == y) 84 { 85 tag[t] += v; 86 max[t] += v; 87 } 88 else 89 { 90 int mid = (l + r) >> 1; 91 92 if (tag[t]) 93 { 94 add(t << 1, l, mid, l, mid, tag[t]); 95 add(t << 1 | 1, mid + 1, r, mid + 1, r, tag[t]); 96 97 tag[t] = 0; 98 } 99 100 if (y <= mid) 101 add(t << 1, l, mid, x, y, v); 102 else if (x > mid) 103 add(t << 1 | 1, mid + 1, r, x, y, v); 104 else 105 add(t << 1, l, mid, x, mid, v), 106 add(t << 1 | 1, mid + 1, r, mid + 1, y, v); 107 108 max[t] = Max(max[t << 1], max[t << 1 | 1]); 109 } 110 } 111 112 signed main(void) 113 { 114 n = nextInt(); 115 m = nextInt(); 116 117 for (int i = 1; i <= n; ++i) 118 { 119 L[i].l = nextInt(); 120 L[i].r = nextInt(); 121 122 L[i].len = L[i].r - L[i].l; 123 124 map[++tot] = L[i].l; 125 map[++tot] = L[i].r; 126 127 ln[i] = L + i; 128 } 129 130 std::sort(map + 1, map + tot + 1); 131 132 { 133 int cnt = 1; 134 135 for (int i = 2; i <= tot; ++i) 136 if (map[i] != map[cnt]) 137 map[++cnt] = map[i]; 138 139 tot = cnt; 140 } 141 142 for (int i = 1; i <= n; ++i) 143 { 144 L[i].l = find(L[i].l); 145 L[i].r = find(L[i].r); 146 } 147 148 std::sort(ln + 1, ln + n + 1, cmp); 149 150 int ans = 1E9 + 7; 151 152 { 153 int cnt = 0; 154 155 for (int i = 1; i <= n; ++i) 156 { 157 while (cnt < n && max[1] < m) 158 { 159 line *t = ln[++cnt]; 160 161 add(1, 1, tot, t->l, t->r, 1); 162 } 163 164 if (max[1] >= m) 165 ans = Min(ans, ln[cnt]->len - ln[i]->len); 166 167 add(1, 1, tot, ln[i]->l, ln[i]->r, -1); 168 } 169 } 170 171 if (ans == 1E9 + 7) 172 puts("-1"); 173 else 174 printf("%d\n", ans); 175 }
@Author: YouSiki