ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

『学习笔记』CDQ分治

2022-01-17 16:33:55  阅读:119  来源: 互联网

标签:10 ch int 分治 mid 笔记 CDQ inline


虽然很久之前学过一遍,但是又忘了 QwQ,于是重新复习了一遍。

CDQ 分治是一个离线算法,也只能用于离线问题的处理上。

主要思想

把当前区间分成两半,向下递归处理。

左边和右边独立的贡献计算出来之后,再计算左边对右边的贡献。

通常会套上一些树状数组之类的数据结构(不然和暴力有啥区别QwQ)

例题

板子题:P3810 【模板】三维偏序(陌上花开)

Solution

先按第一维从小到大排序,对于区间 \((l, r)\),递归处理 \((l, mid)\) 和 \((mid + 1, r)\)。

由于已经按照 \(a\) 排过序,所以左边的 \(a\) 一定不大于右边的 \(a\),就不用考虑了。

对于当前区间 \((l, r)\),再对第二维 \(b\) 从小到大排序。

然后这题就是普通的逆序对问题了,拿两个指针 \(i\) 和 \(j\) 分别扫两段区间 \((l, mid)\) 和 \((mid + 1, r)\)。把 \(C_i <= C_j\) 的点插到树状数组里,再 query 统计答案。

Code

#include <bits/stdc++.h>

using namespace std;

namespace IO{
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const int N = 1e5 + 10;
const int K = 2e5 + 10;
struct ${
    int a, b, c, w, res;
}s[N];
int n, k, tot;
int ans[N];

inline bool cmp1($ x, $ y){
    return x.a != y.a ? x.a < y.a : (x.b != y.b ? x.b < y.b : x.c < y.c);
}

inline bool cmp2($ x, $ y){
    return x.b != y.b ? x.b < y.b : x.c < y.c;
}

int c[K];

inline void add(int x, int y){
    for(; x <= k; x += x & (-x)) c[x] += y;
}

inline int query(int x){
    int res = 0;
    for(; x; x -= x & (-x)) res += c[x];
    return res;
}

inline void CDQ(int l, int r){
    if(l == r) return;
    int mid = (l + r) >> 1;
    CDQ(l, mid), CDQ(mid + 1, r);
    sort(s + l, s + mid + 1, cmp2);
    sort(s + mid + 1, s + r + 1, cmp2);
    int i = l, j = mid + 1;
    while(j <= r){
        while(s[i].b <= s[j].b && i <= mid)
            add(s[i].c, s[i].w), i++;
        s[j].res += query(s[j].c), j++;
    }
    for(j = l; j < i; ++j) add(s[j].c, -s[j].w);
}

int main(){
    n = read(), k = read();
    for(int i = 1; i <= n; ++i)
        s[i] = ($){read(), read(), read()};
    sort(s + 1, s + 1 + n, cmp1);
    int cnt = 0;
    for(int i = 1; i <= n; ++i){
        cnt++;
        if(s[i].a != s[i + 1].a || s[i].b != s[i + 1].b || s[i].c != s[i + 1].c)
            s[++tot] = s[i], s[tot].w = cnt, cnt = 0;
    }
    CDQ(1, tot);
    for(int i = 1; i <= tot; ++i)
        ans[s[i].res + s[i].w - 1] += s[i].w;
    for(int i = 0; i < n; ++i) write(ans[i]), puts("");
    return 0;
}

\[\_EOF\_ \]

标签:10,ch,int,分治,mid,笔记,CDQ,inline
来源: https://www.cnblogs.com/xixike/p/15814045.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有