bzoj3110: [Zjoi2013]K大数查询 【cdq分治&树套树】
模板题,折腾了许久。
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 }
树套树本来想把代表区间的那个线段树开在外面,不是不可以,但是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 }