Luogu | P3810 陌上花开 | cdq 分治 | 三维偏序


Description

有 $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$ 的数量。

对于 $d \in [0, n)$,求 $f(i) = d$ 的数量。


Input Format

第一行两个整数 $n$、$k$,分别表示元素数量和最大属性值。

之后 $n$ 行,每行三个整数 $a_i$、$b_i$、$c_i$,分别表示三个属性值。


Output Format

输出 $n$ 行,第 $d + 1$ 行表示 $f(i) = d$ 的 $i$ 的数量。


Input Sample

Sample 01

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1


Output Sample

Sample 01

3
1
3
0
1
0
1
0
0
1


Data Range

$1≤n≤1\times 10^5$ ,$1≤k≤2\times 10^5$。


Solution

第一维按照 $a$ 直接排序,第二维在 Merge 过程中分治(类似 Mergesort),第三维放进树状数组中查询。当然,也可以 MergeMerge

需要注意的是,题目中有 $a$,$b$,$c$ 相等的情况,需要将 $a$,$b$,$c$ 进行多关键字排序,若完全相等则合并成一个点。每次加入树状数组中的点需要在退出时删除。


Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define swap(x,y) {int t=x; x=y,y=t;}
#define wipe(x,y) memset(x,y,sizeof(x))
#define dbgIn(x) freopen(x".in","r+",stdin)
#define rep(x,y,z) for(int x=y,I=z;x<=I;++x)
#define dbgOut(x) freopen(x".out","w+",stdout)
#define file(x) freopen(x".in","r+",stdin); freopen(x".out","w+",stdout)

#define mid ((L+R)>>1)
#define lowbit(x) (x&(-x))

using std::sort;

inline void Read(int &x){
    x=0; char ch=0; while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return;
}

struct pt{
    int a;
    int b;
    int c;
    int w;
    int id;
    int ans;
    friend bool operator < (pt a,pt b){
        if(a.a==b.a){
            if(a.b==b.b)
                return a.c<b.c;
            return a.b<b.b;
        }
        return a.a<b.a;
    }
}s[100005],t[100005];

int N;
int K;
int ww;
int cnt;

int bit[200005];
int ans_va[100005];

void bitModify(int p,int v){
    while(p<=K){
        bit[p]+=v;
        p+=lowbit(p);
    }
    return;
}

int bitQuery(int p){
    int ret=0;
    while(p){
        ret+=bit[p];
        p-=lowbit(p);
    }
    return ret;
}

int bitQuery(int L,int R){
    return bitQuery(R)-bitQuery(L-1);
}

void merge(int L,int R){
    if(L==R)
        return;
    merge(L,mid);
    merge(mid+1,R);
    int i=L;
    rep(j,mid+1,R){
        while(s[i].b<=s[j].b&&i<=mid){
            bitModify(s[i].c,s[i].w);
            i++;
        }
        s[j].ans+=bitQuery(s[j].c);
    }
    rep(k,L,i-1)
        bitModify(s[k].c,-s[k].w);
    i=L;
    int j=mid+1;
    rep(k,L,R){
        if(i>mid)
            t[k]=s[j++];
        else if(j>R)
            t[k]=s[i++];
        else{
            if(s[i].b==s[j].b){
                if(s[i].c<s[j].c)
                    t[k]=s[i++];
                else
                    t[k]=s[j++];
            }
            else if(s[i].b<s[j].b)
                t[k]=s[i++];
            else
                t[k]=s[j++];
        }
    }
    rep(k,L,R)
        s[k]=t[k];
    return;
}

int main(){
    Read(N);
    Read(K);
    rep(i,1,N){
        s[i].id=i;
        Read(s[i].a);
        Read(s[i].b);
        Read(s[i].c);
    }
    sort(s+1,s+1+N);
    rep(i,1,N){
        ww++;
        if(s[i].a==s[i+1].a&&s[i].b==s[i+1].b&&s[i].c==s[i+1].c)
            continue;
        t[++cnt]=s[i];
        t[cnt].w=ww;
        ww=0;
    }
    rep(i,1,cnt)
        s[i]=t[i];
    merge(1,cnt);
    rep(i,1,cnt)
        ans_va[s[i].ans+s[i].w-1]+=s[i].w;
    rep(i,0,N-1)
        printf("%d\n",ans_va[i]);
    return 0;
}