cdq分治学习笔记

cdq分治:可解决n维偏序

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

题意:有 $ n $ 个元素,第 $ i $ 个元素有 $ a_i,b_i,c_i $ 三个属性,设 $ f(i) $ 表示满足 $ a_j \leq a_i $ 且 $ b_j \leq b_i $ 且 $ c_j \leq c_i $ 且 $ j \ne i $ 的 \(j\) 的数量。对于 $ d \in [0, n) $,求 $ f(i) = d $ 的数量。

做法:
对于第一维 \(a\) , 排序
对于第二位 \(b\) , 归并
对于第三维 \(c\) , 数据结构维护

每次归并考虑区间 \([l,mid]\)\([mid+1,r]\) 的贡献(满足第一维条件)

第二维在左右区间取较小值 左区间add加贡献 右区间query查答案

注意相同元素能互相产生贡献 所以需要去重

#include<bits/stdc++.h>
using namespace std;
#define inl inline
#define ll long long 
#define endl '\n'
#define int ll
const int N=3e5+5;
const int M=1e5+5;
const int inf=0x3f3f3f3f;
const int base=131;
const int mod=1e9+7;
inl int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
inl void write(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inl void writei(int x){write(x);putchar(' ');}
inl void writel(int x){write(x);putchar(endl);}
bool st;
int t,n,k,cnt,c[N],res[N];
struct node{
    int a,b,c,w,ans;
    friend bool operator<(node x,node y){return (x.a^y.a)?x.a<y.a:(x.b^y.b)?x.b<y.b:x.c<y.c;}
}x[N],a[N],b[N];
inl void update(int x,int v){
    for(;x<=k;x+=x&-x)c[x]+=v;
}
inl int query(int x){
    int ans=0;
    for(;x;x-=x&-x)ans+=c[x];
    return ans;
}
inl void cdq(int l,int r){
    if(l==r)return;
    int mid=l+r>>1;
    cdq(l,mid);cdq(mid+1,r);
    int lp=l,rp=mid+1,cnt=l;
    while(lp<=mid&&rp<=r){
        if(a[lp].b<=a[rp].b){
            update(a[lp].c,a[lp].w);
            b[cnt++]=a[lp++];
        }else{
            a[rp].ans+=query(a[rp].c);
            b[cnt++]=a[rp++];
        }
    }
    while(lp<=mid)update(a[lp].c,a[lp].w),b[cnt++]=a[lp++];
    while(rp<=r)a[rp].ans+=query(a[rp].c),b[cnt++]=a[rp++];
    for(int i=l;i<=mid;i++)update(a[i].c,-a[i].w);
    for(int i=l;i<=r;i++)a[i]=b[i];
}
bool ed;
signed main(){
    n=read();k=read();
    for(int i=1;i<=n;i++)x[i]={read(),read(),read(),1};
    sort(x+1,x+n+1);
    for(int i=1;i<=n;i++){
        if((x[i].a^a[cnt].a)||(x[i].b^a[cnt].b)||(x[i].c^a[cnt].c))a[++cnt]=x[i];
        else a[cnt].w++;
    }
    cdq(1,cnt);
    for(int i=1;i<=cnt;i++)res[a[i].ans+a[i].w-1]+=a[i].w;
    for(int i=0;i<n;i++)writel(res[i]);
    return 0;
}
posted @ 2023-11-21 20:40  xiang_xiang  阅读(22)  评论(0)    收藏  举报