BZOJ[3262]陌上花开 CDQ分治+树状数组

本文介绍了一种基于CDQ分治的算法实现,并详细解释了如何通过第一维分治、第二维归并排序和第三维树状数组来解决特定问题。文章提供了完整的代码示例,包括关键的数据结构定义、比较函数和核心的CDQ分治过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门ber~

比较容易的CDQ分治吧..
第一维分治,第二维归并排序,第三维树状数组

题目链接:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define N 200050
using namespace std;
inline int read(){
    int x=0,f=1;char c;
    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
int Timer,n,maxn,top;
int q[N],time[N],cnt[N];
inline void Add(int x,int v){
    for(;x<=maxn;x=x+(x&-x)){
        if(time[x]!=Timer){
            time[x]=Timer;
            q[x]=0;
        }
        q[x]=q[x]+v;
    }
}
inline int Sum(int x){
    int tmp=0;
    for(;x;x=x-(x&-x))
        if(time[x]==Timer)
            tmp=tmp+q[x];
    return tmp;
}
struct Data{
    int x,y,z,num,ans;
}a[N],b[N];
inline bool cmp(Data a,Data b){
    return a.x==b.x?(a.y==b.y?a.z<b.z:a.y<b.y):(a.x<b.x);
}
void CDQ(int l,int r){
    if(l==r) return;
    int mid=(l+r)>>1;
    CDQ(l,mid);CDQ(mid+1,r);
    Timer++;
    int i=l,j=mid+1;
    for(;j<=r;j++){
        while(a[i].y<=a[j].y && i<=mid){
            Add(a[i].z,a[i].num);
            i++;
        }
        a[j].ans+=Sum(a[j].z);
    }
    i=l;j=mid+1;
    int tot=l;
    while(i<=mid && j<=r){
        if(a[i].y<a[j].y) b[tot++]=a[i++];
        else b[tot++]=a[j++];
    }
    while(i<=mid) b[tot++]=a[i++];
    while(j<=r) b[tot++]=a[j++];
    for(int i=l;i<=r;i++)
        a[i]=b[i];
    return;
}
int main(){
    n=read();maxn=read();
    for(int i=1;i<=n;i++){
        a[i].x=read();a[i].y=read();a[i].z=read();
        a[i].num=1;a[i].ans=0;
    }
    sort(a+1,a+n+1,cmp);
    top=1;
    for(int i=2;i<=n;i++){
        if(a[i].x==a[i-1].x && a[i].y==a[i-1].y && a[i].z==a[i-1].z)
            a[top].num++;
        else a[++top]=a[i];
    }
    CDQ(1,top);
    for(int i=1;i<=top;i++)
        cnt[a[i].ans+a[i].num-1]+=a[i].num;
    for(int i=0;i<n;i++)
        printf("%d\n",cnt[i]);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值