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;
}