原题链接:https://www.luogu.org/problemnew/show/P3810
【模板】三维偏序(陌上花开)
题目背景
这是一道模板题
可以使用bitset,CDQ分治,K-DTree等方式解决。
题目描述
有 n n 个元素,第 个元素有 ai a i 、 bi b i 、 ci c i 三个属性,设 f(i) f ( i ) 表示满足 aj≤ai a j ≤ a i 且 bj≤bi b j ≤ b i 且 cj≤ci c j ≤ c i 的 j j 的数量。
对于 ,求 f(i)=d f ( i ) = d 的数量
输入输出格式
输入格式:
第一行两个整数 n n 、 k k ,分别表示元素数量和最大属性值。
之后行,每行三个整数 ai a i 、 bi b i 、 ci c i ,分别表示三个属性值。
输出格式:
输出 n n 行,第行表示 f(i)=d f ( i ) = d 的 i i 的数量。
输入输出样例
输入样例#1:
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
输出样例#1:
3
1
3
0
1
0
1
0
0
1
说明
题解
考虑使用 cdq c d q 分治,第一维直接排序搞掉,第二维 cdq c d q 搞成离线,最后一位上数据结构即可。
左半边对右半边的贡献很好统计,左边为单点加,右边为区间求和。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e6+5;
struct sd{int p,q,r,sum,cot,id;};
bool cmp1(sd a,sd b)
{
if(a.p!=b.p)return a.p<b.p;
if(a.q!=b.q)return a.q<b.q;
return a.r<b.r;
}
bool cmp2(sd a,sd b){return a.q==b.q?(a.r==b.r?a.p<b.p:a.r<b.r):a.q<b.q;}
bool operator !=(sd a,sd b){return a.p!=b.p||a.q!=b.q||a.r!=b.r;}
int sum[M],ans[M],n,tot,base=1;
sd x[M],que[M];
void in()
{
int a;
scanf("%d%d",&n,&a);
while(base<a)base<<=1;
for(int i=1;i<=n;++i)scanf("%d%d%d",&x[i].p,&x[i].q,&x[i].r);
}
void add(int v,int s){v+=base;for(;v;v>>=1)sum[v]+=s;}
int query(int le,int ri)
{
int ans=0;le+=base;ri+=base;
for(;le^ri^1;le>>=1,ri>>=1)
{
if(le&1^1)ans+=sum[le+1];
if(ri&1)ans+=sum[ri-1];
}
return ans;
}
void cdq(int le,int ri)
{
if(le==ri)return;
int mid=(le+ri)>>1;
cdq(le,mid);cdq(mid+1,ri);
sort(que+le,que+ri+1,cmp2);
for(int i=le;i<=ri;++i)
{
if(que[i].id<=mid)add(que[i].r,que[i].cot);
else que[i].sum+=query(0,que[i].r+1);
}
for(int i=le;i<=ri;++i)
if(que[i].id<=mid)add(que[i].r,-que[i].cot);
}
void ac()
{
sort(x+1,x+1+n,cmp1);
for(int i=1;i<=n;++i)
{
if(x[i]!=x[i-1])que[++tot]=x[i],que[tot].id=tot;
++que[tot].cot;
}
cdq(1,tot);
for(int i=1;i<=tot;++i)ans[que[i].sum+que[i].cot-1]+=que[i].cot;
for(int i=0;i<n;++i)printf("%d\n",ans[i]);
}
int main()
{
in();ac();
return 0;
}