CDQ分治
CDQ分治
先%%%陈丹琦巨佬。
大致思路很难讲。
就是对于查询和修改,分开操作。把区间分成左右之后,只处理左修改对右询查询的贡献。
正确性保证:每一对修改和查询都会在分治树上的LCA处被计算。LCA往下就不在一起了,算不到;LCA往上会在同一个半区间,也算不到。
可能讲的不是很清楚,那么我们来看几个例题帮助理解:
CDQ分治还可以优化DP,具体来说就是先把左半边的值求出来,然后拿去更新右半边,然后递归右半边。
有一道模板题是求最长三元单增子序列。注意排序要彻底。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 const int N = 100010; 6 7 template<class T> 8 inline void read(T &x) { 9 x = 0; 10 char c = getchar(); 11 bool f = 0; 12 while(c < '0' || c > '9') { 13 if(c == '-') { 14 f = 1; 15 } 16 c = getchar(); 17 } 18 while(c >= '0' && c <= '9') { 19 x = (x << 3) + (x << 1) + c - 48; 20 c = getchar(); 21 } 22 if(f) { 23 x = (~x) + 1; 24 } 25 return; 26 } 27 28 struct Node { 29 int x, y, z, f, id; 30 }node[N], t[N]; 31 32 int ans = 1, ta[N], n, X[N]; 33 34 inline bool cmp_y(const Node &A, const Node &B) { 35 if(A.y != B.y) { 36 return A.y < B.y; 37 } 38 return A.x > B.x; 39 } 40 41 inline void add(int x, int v) { 42 for(; x <= n; x += x & (-x)) { 43 ta[x] = std::max(ta[x], v); 44 } 45 return; 46 } 47 48 inline int ask(int x) { 49 int t = 0; 50 for(; x > 0; x -= x & (-x)) { 51 t = std::max(t, ta[x]); 52 } 53 return t; 54 } 55 56 inline void del(int x) { 57 for(; x <= n; x += x & (-x)) { 58 ta[x] = 0; 59 } 60 return; 61 } 62 63 void CDQ(int l, int r) { 64 if(l == r) { 65 return; 66 } 67 int mid = (l + r) >> 1; 68 CDQ(l, mid); 69 70 for(int i = l; i <= r; i++) { 71 t[i] = node[i]; 72 t[i].id = i; 73 } 74 std::sort(t + l, t + r + 1, cmp_y); 75 76 for(int i = l; i <= r; i++) { 77 if(t[i].id <= mid) { 78 add(t[i].x, t[i].f); 79 //printf("add %d %d \n", t[i].x, t[i].f); 80 } 81 else { 82 //printf("f %d max %d %d = ask(%d)\n", t[i].id, t[i].f, ask(t[i].x - 1) + 1, t[i].x - 1); 83 t[i].f = std::max(t[i].f, ask(t[i].x - 1) + 1); 84 node[t[i].id].f = t[i].f; 85 ans = std::max(ans, t[i].f); 86 } 87 } 88 89 for(int i = l; i <= mid; i++) { 90 //printf("del : %d \n", node[i].x); 91 del(node[i].x); 92 } 93 CDQ(mid + 1, r); 94 return; 95 } 96 97 int main() { 98 99 read(n); 100 for(int i = 1; i <= n; i++) { 101 read(node[i].y); 102 read(node[i].x); 103 node[i].z = i; 104 node[i].f = 1; 105 X[i] = node[i].x; 106 } 107 std::sort(X + 1, X + n + 1); 108 int xx = std::unique(X + 1, X + n + 1) - X - 1; 109 for(int i = 1; i <= n; i++) { 110 node[i].x = std::lower_bound(X + 1, X + xx + 1, node[i].x) - X; 111 } 112 113 CDQ(1, n); 114 printf("%d", ans); 115 return 0; 116 }