bzoj3262: 陌上花开

Posted oyzx~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3262: 陌上花开相关的知识,希望对你有一定的参考价值。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #define maxn 100005
 7 #define maxk 200005
 8 using namespace std;
 9 
10 int n,k,m,sum[maxk],ans[maxn],sum_[maxn],ans_[maxn];
11 struct date{
12     int x,y,z;
13 }fl[maxn];
14 struct note{
15     int y,z,sum,id;
16 }qs[maxn];
17 
18 bool comp1(date x,date y){
19     if (x.x!=y.x) return x.x<y.x;
20     if (x.y!=y.y) return x.y<y.y;
21     return x.z<y.z;
22 }
23 
24 bool comp2(note x,note y){
25     if (x.y==y.y) return x.z<y.z;
26     return x.y<y.y;
27 }
28 
29 int lowbit(int x){
30     return x&(-x);
31 }
32 
33 void add(int x,int y){
34     for (int i=x;i<=k;i+=lowbit(i)) sum[i]+=y;
35 }
36 
37 int query(int x){
38     int temp=0;
39     for (int i=x;i>0;i-=lowbit(i)){
40         temp+=sum[i];
41     }
42     return temp;
43 }
44 
45 void cdq_solve(int l,int r){
46     if (l==r) return;
47     int mid=(l+r)/2;
48     cdq_solve(l,mid),cdq_solve(mid+1,r);
49     sort(qs+l,qs+mid+1,comp2),sort(qs+mid+1,qs+r+1,comp2);
50     int i=l,j=mid+1,temp=0;
51     while (j<=r){
52         if (i<=mid&&qs[i].y<=qs[j].y) add(qs[i].z,qs[i].sum),i++,temp=i-1;
53         else ans_[qs[j].id]+=query(qs[j].z),j++;
54     }
55     for (int i=l;i<=temp;i++) add(qs[i].z,-qs[i].sum);
56 }
57 
58 int main(){
59     scanf("%d%d",&n,&k),m=0;
60     for (int i=1;i<=n;i++) scanf("%d%d%d",&fl[i].x,&fl[i].y,&fl[i].z);
61     sort(fl+1,fl+n+1,comp1);
62 //    for (int i=1;i<=n;i++) printf("%d %d %d\\n",fl[i].x,fl[i].y,fl[i].z);
63     memset(sum,0,sizeof(sum));
64     memset(ans,0,sizeof(ans));
65     memset(ans_,0,sizeof(ans_));
66     for (int i=1;i<=n;i++){
67         if (fl[i].x==fl[i-1].x&&fl[i].y==fl[i-1].y&&fl[i].z==fl[i-1].z){
68             sum_[m]=++qs[m].sum;
69         }else{
70             qs[++m].sum=1,qs[m].y=fl[i].y,qs[m].z=fl[i].z,qs[m].id=m;
71             sum_[m]=qs[m].sum;
72         }
73     }
74     cdq_solve(1,m);
75     for (int i=1;i<=m;i++) ans[ans_[i]+sum_[i]-1]+=sum_[i];
76     for (int i=0;i<n;i++) printf("%d\\n",ans[i]);
77     return 0;
78 }
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3262

题目大意:有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

输入格式:第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。

以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性。
输出格式:包含N行,分别表示评级为0...N-1的每级花的数量。
 
做法:三维,据说可以用树套树来写(这个以后再尝试写一发),然后这题正解是传统的cdq分治+排序+树状数组,设花的三个属性为x,y,z,我们将花按x为第一关键字,y为第二关键字,z为第三关键字排序,将属性完全相同的缩成一朵花即可,同时维护sum数组,即属形为(x,y,z)的个数,所以在维护树状数组的时候不能+1,而应该+sum[x]。排序后,后面的花只可能会被前面的花所影响,因为在该花后面的花x都比该花大,我们便能想到用cdq分治。
想到这点后,对于合并两个区间信息的问题,我们考虑两个区间分别按y坐标排序,依次第一个区间中的花将z坐标加入树状数组,并及时维护第二个区间中的花的答案,这过程用两个指针维护即可。
cdq分治+树状数组

以上是关于bzoj3262: 陌上花开的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ3262]陌上花开

bzoj3262: 陌上花开

树套树bzoj3262陌上花开

bzoj3262陌上花开 cdq分治

BZOJ 3262--陌上花开

bzoj 3262: 陌上花开