3262: 陌上花开
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 5800 Solved: 2804
[Submit][Status][Discuss]
Description
有n朵花,每朵花有三个属性:花形(s)、颜色©、气味(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
比较明显的三维偏序,于是我们可以考虑使用cdq分治解决,吊打树套树。
因为题目要求我们找等级对应的个数,所以我们需要先去重,因为相同的统计答案时会有问题,因为求个数。
我们先用cdq分治求每朵花的偏序值,然后最后统计次数。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
#define lowbit(x) (x&(-x))
using namespace std;
const int N=100010;
int n,k,a[N<<1],m=200010,res[N],idx;
struct node{
int s,c,m,res,cnt;
node(){
res=0; cnt=1;
}
}t[N],q[N];
bool operator == (const node &s1,const node &s2){
return (s1.s==s2.s&&s1.c==s2.c&&s1.m==s2.m);
}
bool cmps(const node &s1,const node &s2){
return (s1.s==s2.s&&s1.c==s2.c)?(s1.m<s2.m):(s1.s==s2.s?s1.c<s2.c:s1.s<s2.s);
}
bool cmpc(const node &s1,const node &s2){
return (s1.c==s2.c)?(s1.m<s2.m):(s1.c<s2.c);
}
inline void add(int x,int v){
for(int i=x;i<=m;i+=lowbit(i)) a[i]+=v;
}
inline int ask(int x){
int res=0; for(int i=x;i;i-=lowbit(i)) res+=a[i]; return res;
}
void cdq(int l,int r){
if(l==r) return ; int mid=l+r>>1;
cdq(l,mid); cdq(mid+1,r);
int j=l;
for(int i=mid+1;i<=r;i++){
while(j<=mid&&t[j].c<=t[i].c) add(t[j].m,t[j].cnt),j++;
t[i].res+=ask(t[i].m);
}
for(int i=l;i<j;i++) add(t[i].m,-t[i].cnt);
sort(t+l,t+r+1,cmpc);
}
signed main(){
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d %d %d",&q[i].s,&q[i].c,&q[i].m);
sort(q+1,q+1+n,cmps);
for(int i=1;i<=n;i++){
if(i<n&&q[i]==q[i+1]) q[i+1].cnt+=q[i].cnt;
else t[++idx]=q[i];
}
cdq(1,idx);
for(int i=1;i<=idx;i++) res[t[i].res+t[i].cnt-1]+=t[i].cnt;
for(int i=0;i<n;i++) printf("%d\n",res[i]);
return 0;
}