1. 程式人生 > >洛谷P1712 區間

洛谷P1712 區間

題意:給你n個區間,從中選擇m個,使得它們有交,且最長與最短區間的差值最小。

解:這道題我想了好多nlog²n的,nlog²n錯的,nlogn錯的,最後終於想出nlogn的了......

把區間按照長度排序,然後依次再線段樹上加。

如果某一次等於m了,那麼一個一個刪,刪到小於m的時候,更新答案。

證明:那些之前的區間如果想要成為答案,那麼必須是和比當前這個還靠前的區間來組成。

這樣的話當到這一個時,之前的要麼被計算,要麼不會更優。故可以刪掉。

 1 #include <cstdio>
 2 #include <algorithm>
 3
4 const int N = 500010, INF = 0x3f3f3f3f; 5 6 int sum[N << 3], large[N << 3], tag[N << 3], X[N << 1]; 7 8 struct ITV { 9 int r, l, len; 10 inline bool operator <(const ITV &w) const { 11 return len < w.len; 12 } 13 }a[N]; 14 15 inline void pushup(int
o) { 16 int ls = o << 1; 17 int rs = ls | 1; 18 sum[o] = sum[ls] + sum[rs]; 19 large[o] = std::max(large[ls], large[rs]); 20 return; 21 } 22 23 inline void pushdown(int l, int r, int o) { 24 if(tag[o]) { 25 int ls = o << 1; 26 int rs = ls | 1; 27 int
mid = (l + r) >> 1; 28 tag[ls] += tag[o]; 29 tag[rs] += tag[o]; 30 sum[ls] += (mid - l + 1) * tag[o]; 31 sum[rs] += (r - mid) * tag[o]; 32 large[ls] += tag[o]; 33 large[rs] += tag[o]; 34 tag[o] = 0; 35 } 36 return; 37 } 38 39 inline void add(int L, int R, int v, int l, int r, int o) { 40 if(L <= l && r <= R) { 41 tag[o] += v; 42 sum[o] += v * (r - l + 1); 43 large[o] += v; 44 return; 45 } 46 pushdown(l, r, o); 47 int mid = (l + r) >> 1; 48 if(L <= mid) { 49 add(L, R, v, l, mid, o << 1); 50 } 51 if(mid < R) { 52 add(L, R, v, mid + 1, r, o << 1 | 1); 53 } 54 pushup(o); 55 return; 56 } 57 58 int main() { 59 60 int n, m; 61 scanf("%d%d", &n, &m); 62 for(int i = 1; i <= n; i++) { 63 scanf("%d%d", &a[i].l, &a[i].r); 64 a[i].len = a[i].r - a[i].l; 65 X[i << 1] = a[i].l; 66 X[(i << 1) - 1] = a[i].r; 67 } 68 std::sort(a + 1, a + n + 1); 69 std::sort(X + 1, X + (n << 1) + 1); 70 int t = std::unique(X + 1, X + (n << 1) + 1) - X - 1; 71 int j = 1, ans = INF; 72 for(int i = 1; i <= n; i++) { 73 a[i].l = std::lower_bound(X + 1, X + t + 1, a[i].l) - X; 74 a[i].r = std::lower_bound(X + 1, X + t + 1, a[i].r) - X; 75 add(a[i].l, a[i].r, 1, 1, t, 1); 76 while(large[1] >= m) { 77 add(a[j].l, a[j].r, -1, 1, t, 1); 78 //printf("large[1] = %d ans = %d \n i = %d j = %d \n", large[1], ans, i, j); 79 ans = std::min(ans, a[i].len - a[j].len); 80 j++; 81 } 82 } 83 if(ans == INF) { 84 ans = -1; 85 } 86 printf("%d\n", ans); 87 return 0; 88 }
AC程式碼

這個sum其實是不必要的。

然後我還用動態開點寫了一發......被卡空間了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 const int N = 500010, INF = 0x3f3f3f3f;
 5 
 6 int large[N * 31], tag[N * 31], root, ls[N * 31], rs[N * 31], tot;
 7 
 8 struct ITV {
 9     int r, l, len;
10     inline bool operator <(const ITV &w) const {
11        return len < w.len;
12     }
13 }a[N];
14 
15 inline void pushup(int o) {
16     large[o] = std::max(large[ls[o]], large[rs[o]]);
17     return;
18 }
19 
20 inline void pushdown(int l, int r, int o) {
21     if(tag[o]) {
22         int mid = (l + r) >> 1;
23         if(ls[o]) {
24             large[ls[o]] += tag[o];
25             tag[ls[o]] += tag[o];
26         }
27         if(rs[o]) {
28             large[rs[o]] += tag[o];
29             tag[rs[o]] += tag[o];
30         }
31         tag[o] = 0;
32     }
33     return;
34 }
35 
36 inline void add(int L, int R, int v, int l, int r, int &o) {
37     if(!o) {
38         o = ++tot;
39     }
40     if(L <= l && r <= R) {
41         tag[o] += v;
42         large[o] += v;
43         return;
44     }
45     if(!ls[o]) {
46         ls[o] = ++tot;
47     }
48     if(!rs[o]) {
49         rs[o] = ++tot;
50     }
51     pushdown(l, r, o);
52     int mid = (l + r) >> 1;
53     if(L <= mid) {
54         add(L, R, v, l, mid, ls[o]);
55     }
56     if(mid < R) {
57         add(L, R, v, mid + 1, r, rs[o]);
58     }
59     pushup(o);
60     return;
61 }
62 
63 int main() {
64 
65     int n, m, lm = 0;
66     scanf("%d%d", &n, &m);
67     for(int i = 1; i <= n; i++) {
68         scanf("%d%d", &a[i].l, &a[i].r);
69         a[i].len = a[i].r - a[i].l;
70         lm = std::max(lm, a[i].r);
71     }
72     std::sort(a + 1, a + n + 1);
73     int j = 1, ans = INF;
74     for(int i = 1; i <= n; i++) {
75         add(a[i].l, a[i].r, 1, 1, lm, root);
76         while(large[1] >= m) {
77             add(a[j].l, a[j].r, -1, 1, lm, root);
78             //printf("large[1] = %d  ans = %d \n i = %d j = %d \n", large[1], ans, i, j);
79             ans = std::min(ans, a[i].len - a[j].len);
80             j++;
81         }
82     }
83     if(ans == INF) {
84         ans = -1;
85     }
86     printf("%d\n", ans);
87     return 0;
88 }
95分動態開點