LOJ112三维偏序

题目描述
有\(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\) 的 \(i\) 的数量。
输入格式
第一行两个整数\(n 、k\),分别表示元素数量和最大属性值。

之后 \(n\) 行,每行三个整数\(a_i 、b_i、c_i\),分别表示三个属性值。
输出格式
输出 \(n\) 行,第 \(d+1\) 行表示 \(f(i)=d\) 的 \(i\) 的数量。
样例
输入复制

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

输出复制

3
1
3
0
1
0
1
0
0
1

数据范围与提示
\(n\leq100000\)
\(k\leq200000\)

CDQ分治模板题目

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=2e5+10;
struct node
{
    int a,b,c,cnt,id;
    bool operator < (const node & x)const 
    {
        if(a!=x.a)return a<x.a;
        if(b!=x.b)return b<x.b;
        if(c!=x.c)return c<x.c;
        return 0;
    }
}sz[maxn],f[maxn];
int n,m;
int ans[maxn];
int sum[maxm];
void add(int pos,int v)
{
    for(int i=pos;i<=m;i+=(i&(-i)))
        sum[i]+=v;
}
int query(int pos)
{
    int ans=0;
    for(int i=pos;i;i-=(i&(-i)))
        ans+=sum[i];
    return ans;
}
void cdq(int l,int r)
{
    if(l==r)return ;
    int mid=(l+r)>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int q=l,h=mid+1,p=l;
    while(q<=mid&&h<=r)
    {
        if(sz[q].b<=sz[h].b)
        {
            f[p]=sz[q];
            add(sz[q].c,sz[q].cnt);
            ++p,++q;
        }
        else
        {
            f[p]=sz[h];
            int tp=query(sz[h].c);
            ans[sz[h].id]+=tp;
            ++p;++h;
        }
    }
    while(q<=mid)
    {
        f[p]=sz[q];
        add(sz[q].c,sz[q].cnt);
        ++p,++q;
    }
    while(h<=r)
    {
        f[p]=sz[h];
        int tp=query(sz[h].c);
        ans[sz[h].id]+=tp;
        ++p;++h;
    }
    for(int i=1;i<=m;++i)sum[i]=0;
    for(int i=l;i<=r;++i)sz[i]=f[i];
}
int rt[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d%d%d",&sz[i].a,&sz[i].b,&sz[i].c),sz[i].cnt=1;
    sort(sz+1,sz+1+n);
    int nn=1;sz[1].id=1;
    for(int i=2;i<=n;++i)
    {
        if(sz[nn].a==sz[i].a&&sz[nn].b==sz[i].b&&sz[nn].c==sz[i].c)sz[nn].cnt++;
        else 
        {
            ++nn;sz[nn].a=sz[i].a;sz[nn].b=sz[i].b;sz[nn].c=sz[i].c;sz[nn].cnt=1;sz[nn].id=nn;
        }
    }
    cdq(1,nn);
    for(int i=1;i<=nn;++i)ans[sz[i].id]+=sz[i].cnt;
    for(int i=1;i<=nn;++i)rt[ans[sz[i].id]]+=sz[i].cnt;
    for(int i=1;i<=n;++i)printf("%d\n",rt[i]);
    return 0;
}
上一篇:CDQ分治


下一篇:acwing 428 数列 ——练习二进制位运算与二进制映射比较经典的题目