CDQ分治

Posted

tags:

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

我tm终于把三维偏序调对了

CDQ分治是一种进行计算时的降维手段,简单说大家都知道在进行一维偏序时我们只需要排序,二维偏序则可以用树状数组+排序,这之中树状数组就是一个降维手段,它将二维偏序降维,然后就可以用一维偏序做了。CDQ和树套树也是同理,所以可能会出四维偏序(CDQ+树套树)???

CDQ的思想主要是分治,然后计算前半部分对后半部分产生的影响所以说常规分治其实是恰好前半部分对后半部分没影响的CDQ??

下面就是代码(三维偏序),思路是排序一维,CDQ一维,CDQ中用树状数组统计第三维

重点:

1.CDQ分治中树状数组一定不要memset!把树状数组的加法减回去就好了;

2.排序后再记一次rank可以大幅降低编程难度;

3.对于重复数据我们可以记录每个数据排序最靠后的一个,它的答案就是所有这个数据的答案(想想为什么)

代码略丑

 

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
struct data
{
    int x,y,z,num,num2;
    bool operator < (const data &a) const
    {
        if(x==a.x)
        {
            if(y==a.y) return z<a.z;
            return y<a.y;
        }
        return x<a.x;
    }
    bool operator != (const data &a) const
    {
        return ((x!=a.x)||(y!=a.y)||(z!=a.z));
    }
}P[100010];
bool cmp(data a,data b)
{
    if(a.y==b.y) 
    {
        return a.num2<b.num2;
    }
    return a.y<b.y;
}
int n,k;
int c[450010],ans[100010],ans2[100010];
int to[100010];
void add(int p,int x){for(int i=p;i<=400010;i+=lowbit(i))c[i]+=x;}
int query(int p){int tmp=0;for(int i=p;i>=1;i-=lowbit(i))tmp+=c[i];return tmp;}
void cdq(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)/2;
    data mi=P[mid];
    cdq(l,mid);cdq(mid+1,r);
    sort(P+l,P+r+1,cmp);
    for(int i=l;i<=r;i++)
    {
        if(P[i].num2<=mi.num2) 
        {
            add(P[i].z,1);
        }
        else 
        {
            ans[P[i].num]+=query(P[i].z);
        }
    }
    for(int i=l;i<=r;i++)
    {
        if(P[i].num2<=mi.num2) add(P[i].z,-1);
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        P[i].num=i;
        scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].z);
    } 
    sort(P+1,P+n+1);
    P[n+1].x=-1;
    int flag=1;
    for(int i=1;i<=n;i++)
    {
        P[i].num2=i;
        if(P[i]!=P[i+1])
        {
            for(int j=flag;j<=i;j++) to[P[j].num]=P[i].num;
            flag=i+1;    
        } 
    }
    cdq(1,n);
    for(int i=1;i<=n;i++)
    {
        ans2[ans[to[i]]]++;
    }
    for(int i=0;i<n;i++)
    {
        printf("%d\n",ans2[i]);
    }
}
CDQ三维偏序

 

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

模板:CDQ分治

初窥CDQ分治

HDU 3507 Print Article(CDQ分治+分治DP)

bzoj 2683 简单题 cdq分治

bzoj4237: 稻草人 cdq分治 单调栈

cdq分治浅谈