cdq分治学习

Posted starve

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cdq分治学习相关的知识,希望对你有一定的参考价值。

经典问题:三维偏序

题:https://www.luogu.org/problem/P3810

一般处理:先按照自己定义的第一维排好序,那么在接下来的俩维判断中,我们就可以消除第一维造成的影响,接着用以前学过的分治排序法来处理第二维,以第二维作为排序对象,对于分治的[l,midd]和[midd+1,r]这俩个区间

对于区间 [m+1, r]中的某个元素x,将区间 [l, m] 的第二维小于x的元素的按第三维的权值加入树状数组,

最后区间 [l, m] 对区间 x 的贡献就是查询树状数组中小于x第三维的个数

可以边进行分治边进行归并排序,树状数组要及时清空

技术图片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
    int sum=0,x=1;
    char ch=getchar();
    while(ch<0||ch>9)
        if(ch==-)
            x=0;
        ch=getchar();
    
    while(ch>=0&&ch<=9)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return x?sum:-sum;

inline void write(ll x)
    if(x<0)
        putchar(-),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+0);

#define pb push_back
#define lowbit(x) (x&(-x))
const int M=2e5+5;
struct node
    int x,y,z,cnt,ans;
    bool operator < (const node &b)const
        if(x!=b.x)
            return x<b.x;
        else if(y!=b.y)
            return y<b.y;
        else
            return z<b.z;
    
a[M>>1],temp[M>>1];
int tree[M];
int n,k;
int ANS[M];
void add(int i,int x)
    while(i<=k)
        tree[i]+=x;
        i+=lowbit(i);
    

int query(int i)
    int res=0;
    while(i)
        res+=tree[i];
        i-=lowbit(i);
    
    return res;

void cdq(int l,int r)
    if(l==r)
        a[l].ans+=a[l].cnt-1;
        return ;
    
    int midd=(l+r)>>1;
    cdq(l,midd);
    cdq(midd+1,r);
    int i=l,j=midd+1,op=l;
    while(j<=r)
        while(i<=midd&&a[i].y<=a[j].y)
            add(a[i].z,a[i].cnt);
            temp[op++]=a[i];
            i++;
        
        a[j].ans+=query(a[j].z);
        temp[op++]=a[j];
        j++;
    
    for(j=l;j<i;j++)
        add(a[j].z,-a[j].cnt);
    while(i<=midd)
        temp[op++]=a[i],i++;
    
    for(i=l;i<=r;i++)
        a[i]=temp[i];

int main()
    n=read(),k=read();
    for(int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read(),a[i].z=read();
    sort(a+1,a+1+n);
    int now=1,cnt=0;
    for(int i=2;i<=n;i++)
        if(a[i-1].x==a[i].x&&a[i-1].y==a[i].y&&a[i-1].z==a[i].z)
            now++;
        else
            a[++cnt]=a[i-1];
            a[cnt].cnt=now;
            a[cnt].ans=0;
            now=1;
        
        
    
    a[++cnt]=a[n];
    a[cnt].cnt=now;
    a[cnt].ans=0;
    cdq(1,cnt);
    for(int i=1;i<=cnt;i++)
        ANS[a[i].ans]+=a[i].cnt;
    for(int i=0;i<n;i++)
        printf("%d\n",ANS[i]);
    return 0;    
View Code

 

以上是关于cdq分治学习的主要内容,如果未能解决你的问题,请参考以下文章

CDQ分治·学习笔记

学习笔记: cdq分治

[学习笔记] CDQ分治

cdq分治学习

cdq分治浅谈

CDQ分治学习