首页 > 技术文章 > bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】

y7070 2015-12-23 12:40 原文

  模板题,折腾了许久。

  cqd分治整体二分,感觉像是把询问分到答案上。

  1 #include <bits/stdc++.h>
  2 #define rep(i, a, b) for (int i = a; i <= b; i++)
  3 #define drep(i, a, b) for (int i = a; i >= b; i--)
  4 #define REP(i, a, b) for (int i = a; i < b; i++)
  5 #define pb push_back
  6 #define mp make_pair
  7 #define clr(x) memset(x, 0, sizeof(x))
  8 #define xx first
  9 #define yy second
 10 using namespace std;
 11 typedef long long i64;
 12 typedef pair<int, int> pii;
 13 const int inf = ~0U >> 1;
 14 const i64 INF = ~0ULL >> 1;
 15 template <typename T> void Max(T &a, T &b) { if (a < b) a = b; }
 16 template <typename T> void Min(T &a, T &b) { if (a > b) a = b; }
 17 //******************************************
 18  
 19 const int maxn = 50005;
 20  
 21 struct Seg_Tree {
 22     int sum[maxn << 3], lazy[maxn << 3];
 23     void Push_down(int o, int m) {
 24         if (!lazy[o]) return;
 25         lazy[o << 1] += lazy[o], lazy[o << 1 | 1] += lazy[o];
 26         sum[o << 1] += lazy[o] * (m - (m >> 1)), sum[o << 1 | 1] += lazy[o] * (m >> 1);
 27         lazy[o] = 0;
 28     }
 29     void Push_up(int o) { sum[o] = sum[o << 1] + sum[o << 1 | 1]; }
 30     void update(int o, int l, int r, int ql, int qr, int v) {
 31         if (ql <= l && r <= qr) {
 32             lazy[o] += v;
 33             sum[o] += v * (r - l + 1);
 34             return;
 35         }
 36         Push_down(o, r - l + 1);
 37         int mid = l + r >> 1;
 38         if (ql <= mid) update(o << 1, l, mid, ql, qr, v);
 39         if (qr > mid) update(o << 1 | 1, mid + 1, r, ql, qr, v);
 40         Push_up(o);
 41     }
 42     int query(int o, int l, int r, int ql, int qr) {
 43         if (ql <= l && r <= qr) return sum[o];
 44         Push_down(o, r - l + 1);
 45         int mid = l + r >> 1;
 46         int ret(0);
 47         if (ql <= mid) ret += query(o << 1, l, mid, ql, qr);
 48         if (qr > mid) ret += query(o << 1 | 1, mid + 1, r, ql, qr);
 49         return ret;
 50     }
 51     void CLR() { clr(sum), clr(lazy); }
 52 } T;
 53  
 54 struct Complex {
 55     int flag, x, y, c, id;
 56     inline bool operator < (const Complex &A) const {
 57         return id < A.id;
 58     }
 59 } src[maxn];
 60  
 61 int N, ans[maxn], v[maxn];
 62 void cdq(int ansl, int ansr, int l, int r) {
 63     if (ansl == ansr) {
 64         rep(i, l, r) if (src[i].flag == 2) ans[src[i].id] = ansl;
 65         return;
 66     }
 67     if (l > r) return;
 68     sort(src + l, src + r + 1);
 69     int m = ansl + ansr + 1 >> 1;
 70     int j = l;
 71     rep(i, l, r) {
 72         if (src[i].flag == 1) {
 73             if (src[i].c >= m) T.update(1, 1, N, src[i].x, src[i].y, 1), v[i] = 1;
 74             else v[i] = 0;
 75         }
 76         else {
 77             int t = T.query(1, 1, N, src[i].x, src[i].y);
 78             if (t >= src[i].c) v[i] = 1;
 79             else src[i].c -= t, v[i] = 0;
 80         }
 81         j += !v[i];
 82     }
 83     rep(i, l, r)
 84         if (src[i].flag == 1)
 85             if (src[i].c >= m) T.update(1, 1, N, src[i].x, src[i].y, -1);
 86     int t = j - 1;
 87     if (j != l)
 88     rep(i, l, t) {
 89         while (j < r && v[j]) ++j;
 90         if (v[i]) swap(src[i], src[j]), swap(v[i], v[j]), ++j;
 91     }
 92     cdq(ansl, m - 1, l, t);
 93     cdq(m, ansr, t + 1, r);
 94 }
 95  
 96 int read() {
 97     int l = 1, s = 0; char ch = getchar();
 98     while (ch < '0' || ch > '9') { if (ch == '-') l = -1; ch = getchar(); }
 99     while (ch >= '0' && ch <= '9') { s = (s << 1) + (s << 3) + ch - '0'; ch = getchar(); }
100     return s * l;
101 }
102 int main() {
103     int n, m; scanf("%d%d", &n, &m);
104     rep(i, 1, m) scanf("%d%d%d%d", &src[i].flag, &src[i].x, &src[i].y, &src[i].c), src[i].id = i;
105     N = n;
106     cdq(-n, n, 1, m);
107     sort(src + 1, src + 1 + m);
108     rep(i, 1, m) if (src[i].flag == 2) printf("%d\n", ans[i]);
109     return 0;
110 }
View Code

 

  树套树本来想把代表区间的那个线段树开在外面,不是不可以,但是lazy标记可能要一个vector才能存,因为我要存多个种类。

  然后就只能把代表数字那一维开在外面,代表这一段数字在1-n这个区间的分布情况,这样就可以在第二层线段树上打lazy标记。

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (register int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (register int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (register int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = ~0U >> 1;
14 const i64 INF = ~0ULL >> 1;
15 //*******************************
16  
17 const int maxn = 200005, maxnn = 20000005;
18  
19 int root[maxn << 2];
20 int ls[maxnn], rs[maxnn], sum[maxnn], lazy[maxnn];
21  
22 int ndtot, n, N;
23 inline void Push_up(int o) { sum[o] = sum[ls[o]] + sum[rs[o]]; }
24 inline void Push_down(int o, int m) {
25     if (!lazy[o]) return;
26     if (!ls[o]) ls[o] = ++ndtot;
27     if (!rs[o]) rs[o] = ++ndtot;
28     lazy[ls[o]] += lazy[o], lazy[rs[o]] += lazy[o];
29     sum[ls[o]] += lazy[o] * (m - (m >> 1)), sum[rs[o]] += lazy[o] * (m >> 1);
30     lazy[o] = 0;
31 }
32 void update(int &k, int l, int r, int ql, int qr, int v) {
33     if (!k) k = ++ndtot;
34     if (ql <= l && r <= qr) {
35         sum[k] += v * (r - l + 1);
36         lazy[k] += v;
37         return;
38     }
39     int mid = l + r >> 1;
40     Push_down(k, r - l + 1);
41     if (ql <= mid) update(ls[k], l, mid, ql, qr, v);
42     if (qr > mid) update(rs[k], mid + 1, r, ql, qr, v);
43     Push_up(k);
44 }
45 void insrt(int o, int l, int r, int ql, int qr, int c) {
46     while (l != r) {
47         int mid = l + r >> 1;
48         update(root[o], 1, n, ql, qr, 1);
49         if (c <= mid) o <<= 1, r = mid;
50         else o = o << 1 | 1, l = mid + 1;
51     }
52     update(root[o], 1, n, ql, qr, 1);
53 }
54  
55 int query(int o, int l, int r, int ql, int qr) {
56     if (!o) return 0;
57     if (ql <= l && r <= qr) return sum[o];
58     Push_down(o, r - l + 1);
59     int mid = l + r >> 1;
60     int ret(0);
61     if (ql <= mid) ret += query(ls[o], l, mid, ql, qr);
62     if (qr > mid) ret += query(rs[o], mid + 1, r, ql, qr);
63     return ret;
64 }
65 int solve(int o, int l, int r, int ql, int qr, int c) {
66     while (l != r) {
67         int mid = l + r >> 1;
68         int t = query(root[o << 1 | 1], 1, n, ql, qr);
69         if (t >= c) l = mid + 1, o = o << 1 |1;
70         else r = mid, o = o << 1, c -= t;
71     }
72     return l;
73 }
74  
75 int main() {
76     int m; scanf("%d%d", &n, &m);
77     N = 2 * n + 1;
78     while (m--) {
79         int flag, a, b, c; scanf("%d%d%d%d", &flag, &a, &b, &c);
80         if (flag == 1) {
81             c += n + 1;
82             insrt(1, 1, N, a, b, c);
83         }
84         else printf("%d\n", solve(1, 1, N, a, b, c) - n - 1);
85     }
86 }
View Code

 

推荐阅读