BZOJ 3262: 陌上花开
http://www.lydsy.com/JudgeOnline/problem.php?id=3262
题意:
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
输出包含N行,分别表示评级为0...N-1的每级花的数量。
数据:
Time Limit: 20 Sec , Memory Limit: 256 MB
N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值
思路:
1. 偏序问题 [三维(x,y,z)], CDQ分治。
2. 对 x 分治 , 对 y 排序 ,对 z 使用树状数组维护。
(PS:还有树套树的做法 , 占坑后补。)
代码:
#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;
typedef long long LL;
const int N = 200005;
int n,m;
struct nd
{
int x,y,z;
int cnt,ans;
}s[N];
int bt[N];
int num[N];
int pos;
void add(int a,int x) {for (int i=a;i<=m;i+=i&(-i)) bt[i]+=x; }
int sum(int x) {int res=0; for (int i=x;i>0;i-=i&(-i)) res+=bt[i]; return res; }
int cmpx(nd a,nd b)
{
if (a.x!=b.x)
return a.x<b.x;
if (a.y!=b.y)
return a.y<b.y;
return a.z<b.z;
}
int cmpy(nd a,nd b)
{
if (a.y!=b.y)
return a.y<b.y;
return a.z<b.z;
}
void cdq(int l,int r)
{
if (l==r)
{
s[l].ans+=s[l].cnt-1;
return;
}
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
sort(s+l,s+mid+1,cmpy);
sort(s+mid+1,s+r+1,cmpy);
int j=l;
for (int i=mid+1;i<=r;i++)
{
for (;j<=mid && s[j].y<=s[i].y ;j++)
add(s[j].z,s[j].cnt);
s[i].ans+=sum(s[i].z);
}
for (int i=l;i<j;i++)
add(s[i].z,-s[i].cnt);
// sort(s+l,s+r+1,cmpy);
}
int main()
{
while (~scanf("%d %d", &n, &m))
{
memset(s,0,sizeof(s));
memset(bt,0,sizeof(bt));
memset(num,0,sizeof(num));
pos=0;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].z);
s[i].ans=1;
}
sort(s+1,s+1+n,cmpx);
for (int i=1;i<=n;i++)
{
if (i!=1 && s[i-1].x==s[i].x && s[i-1].y==s[i].y && s[i-1].z==s[i].z)
s[pos].cnt++;
else
{
s[++pos]=s[i];
s[pos].cnt=1;
}
}
cdq(1,pos);
// sort(s+1,s+1+pos,cmpx);
for (int i=1;i<=pos;i++)
num[s[i].ans]+=s[i].cnt;
for (int i=1;i<=n;i++)
printf("%d\n",num[i]);
}
return 0;
}
/*
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
*/