CDQ分治

CDQ分治

先%%%陈丹琦巨佬。

大致思路很难讲。

就是对于查询和修改,分开操作。把区间分成左右之后,只处理左修改对右询查询的贡献。

正确性保证:每一对修改和查询都会在分治树上的LCA处被计算。LCA往下就不在一起了,算不到;LCA往上会在同一个半区间,也算不到。

可能讲的不是很清楚,那么我们来看几个例题帮助理解:

陌上花开

Mokia

天使玩偶

动态逆序对

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 }
AC代码

洛谷P4849 寻找宝藏

 

posted @ 2018-04-18 12:59  huyufeifei  阅读(...)  评论(...编辑  收藏