题目
Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
Output
包含N行,分别表示评级为0…N-1的每级花的数量。
Sample Input
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
Sample Output
3
1
3
0
1
0
1
0
0
1
HINT
1 <= N <= 100,000, 1 <= K <= 200,000
cdq分治
这题跟想象中的cdq分治是差不多的,比较好理解。
引用网上的话:第一维排序,第二维cdq分治,第三维树状数组。
也就是先按第一维进行排序,然后把第二维cdq分治一下,每次先往下cdq(l,mid),cdq(mid+1,r),由于cdq结束之后的第二维是有序的,那么就可以用树状数组统计前半部分对后半部分的贡献了。
但还有个问题就是如果有两个所有参数都相同的花怎么办。我参考的是网上的办法:所有相同的都只算一朵就好了,但在处理的时候还是要把所有的都算进去。
总结起来其原理就是跟归并排序差不多。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 200005
using namespace std;
int c[M],n,m,ans[N];
struct data{int x,y,z,ans,size;}q[N],t[N],f[N];
bool cmp(data a,data b)
{
return a.x<b.x||a.x==b.x&&a.y<b.y||a.x==b.x&&a.y==b.y&&a.z<b.z;
}
void ins(int x,int y)
{
while (x<=m)
{
c[x]+=y;
x+=x&(-x);
}
}
int query(int x)
{
int ans=0;
while (x)
{
ans+=c[x];
x-=x&(-x);
}
return ans;
}
void cdq(int l,int r)
{
if (l>=r) return;
int mid=(l+r)/2;
cdq(l,mid);cdq(mid+1,r);
int i=l;
for (int j=mid+1;j<=r;j++)
{
while (q[i].y<=q[j].y&&i<=mid)
{
ins(q[i].z,q[i].size);
i++;
}
q[j].ans+=query(q[j].z);
}
i=l;
for (int j=mid+1;j<=r;j++)
while (q[i].y<=q[j].y&&i<=mid)
{
ins(q[i].z,-q[i].size);
i++;
}
i=l;int j=mid+1,k=l;
while (i<=mid&&j<=r)
if (q[i].y<q[j].y) t[k++]=q[i++];
else t[k++]=q[j++];
while (i<=mid) t[k++]=q[i++];
while (j<=r) t[k++]=q[j++];
for (int i=l;i<=r;i++)
q[i]=t[i];
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z);
sort(f+1,f+n+1,cmp);
int size=0,tot=0;
for (int i=1;i<=n;i++)
{
size++;
if (f[i].x!=f[i+1].x||f[i].y!=f[i+1].y||f[i].z!=f[i+1].z)
{
q[++tot]=f[i];
q[tot].size=size;
size=0;
}
}
cdq(1,tot);
for (int i=1;i<=tot;i++)
ans[q[i].ans+q[i].size-1]+=q[i].size;
for (int i=0;i<n;i++)
printf("%d\n",ans[i]);
return 0;
}