[BZOJ3262]陌上花开
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
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
1
3
0
1
0
1
0
0
1
排序消去$a$的影响,归并排序的过程消除$b$的影响,然后利用树状数组统计答案
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define M 200010 6 using namespace std; 7 int n,k; 8 int val[M],ans[M]; 9 struct CDQ{int a,b,c,val,ans;}p[M],tmp[M]; 10 bool cmp(CDQ a,CDQ b) { 11 return a.a==b.a?(a.b==b.b?a.c<b.c:a.b<b.b):a.a<b.a; 12 } 13 void change(int loc,int v) { 14 for(int i=loc;i<=k;i+=i&(-i)) val[i]+=v; 15 } 16 int query(int loc) { 17 int ans=0; 18 for(int i=loc;i;i-=i&(-i)) ans+=val[i]; 19 return ans; 20 } 21 void solve(int l,int r) { 22 if(l==r) return;int mid=(l+r)/2; 23 solve(l,mid),solve(mid+1,r); 24 int t1=l,t2=mid+1,now=l; 25 while(t1<=mid||t2<=r) { 26 if((t1<=mid&&p[t1].b<=p[t2].b)||t2>r) { 27 change(p[t1].c,p[t1].val); 28 tmp[now++]=p[t1++]; 29 } 30 else { 31 p[t2].ans+=query(p[t2].c); 32 tmp[now++]=p[t2++]; 33 } 34 } 35 for(int i=l;i<=mid;i++) change(p[i].c,-p[i].val); 36 for(int i=l;i<=r;i++) p[i]=tmp[i]; 37 } 38 int main() { 39 scanf("%d%d",&n,&k); 40 for(int i=1;i<=n;i++) { 41 scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c); 42 p[i].val=1; 43 } 44 sort(p+1,p+1+n,cmp);int now=1; 45 for(int i=2;i<=n;i++) { 46 if(p[i].a==p[now].a&&p[i].b==p[now].b&&p[i].c==p[now].c) p[now].val++; 47 else p[++now]=p[i]; 48 } 49 solve(1,now); 50 for(int i=1;i<=now;i++) ans[p[i].ans+p[i].val-1]+=p[i].val; 51 for(int i=0;i<n;i++) printf("%d\n",ans[i]); 52 return 0; 53 }