[BZOJ3262]陌上花开

陌上花开

题目描述

有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的每级花的数量。

样例

样例输入

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
1
3
0
1
0
1
0
0
1

膜拜CDQ小姐姐

CDQ分治一般情况下会用来解决三维偏序问题,一般的套路是第一维直接快排,然后进行CDQ分治,在分治过程中通过归并再次使得第二维有序,当然,不归并可以再次对部分数据快排,打起来肯定快排爽,不过过程中要处理的东西处理起来应该也有点难受,如果代码能力是大佬,就当刚才什么都没说,由于进行操作前已经保证了第一维有序,左区间均可对右区间作出贡献,所以在归并第二维时第一维已经不重要了,第三维的有序一般通过树状数组等数据结构实现,需要注意的是对于维护第三维的数据结构需要每次清空,但是千万不要memset之类的全部清空,别觉得memset一句话就快,他就是O(n),只需要清空当前区间,不然很可能T到飞起,上述就是CDQ分治的基本思路

陌上花开是CDQ最经典的三维偏序问题,思路就是上述那个,这题需要注意的是由于等于的存在,要在排序之后去重,其他的,树状数组记得打对,存的是第三维,记得不管是数组范围还是操作结尾,均是k而不是n,来自WA了6遍的调了一天半的过来人的提醒,图就不贴了,丢人

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define maxn 100100
 5 using namespace std;
 6 struct node{
 7     int s,c,m,sum,js;
 8 }a[maxn],gb[maxn];
 9 int n,k,tot;
10 int c[maxn*2],ans[maxn];
11 bool cmp(const node &a,const node &b)
12 {
13     if(a.s!=b.s)  return a.s<b.s;
14     if(a.c!=b.c)  return a.c<b.c;
15     return a.m<b.m;
16 }
17 int lowbit(int x)
18 {
19     return x&(-x);
20 }
21 void add(int x,int w)
22 {
23     for(int i=x;i<=k;i+=lowbit(i))  c[i]+=w;
24 }
25 int getsum(int w)
26 {
27     int ans=0;
28     for(int i=w;i;i-=lowbit(i))  ans+=c[i];
29     return ans;
30 }
31 void cdq(int l,int r)
32 {
33     if(l==r)  return ;
34     int mid=(l+r)>>1,ll=l,rr=mid+1,zz=l;
35     cdq(l,mid);  cdq(mid+1,r);
36     while(ll<=mid&&rr<=r)
37     {
38         if(a[ll].c<=a[rr].c)  {add(a[ll].m,a[ll].js);  gb[zz++]=a[ll++];}
39         else  {a[rr].sum+=getsum(a[rr].m);  gb[zz++]=a[rr++];}
40     }
41     while(ll<=mid)  {add(a[ll].m,a[ll].js);  gb[zz++]=a[ll++];}
42     while(rr<=r)  {a[rr].sum+=getsum(a[rr].m);  gb[zz++]=a[rr++];}
43     for(int i=l;i<=r;++i)
44     {
45         if(i<=mid)  add(a[i].m,-a[i].js);
46         a[i]=gb[i];
47     }
48 }
49 int main()
50 {
51     scanf("%d%d",&n,&k);
52     for(int i=1;i<=n;++i)  scanf("%d%d%d",&a[i].s,&a[i].c,&a[i].m);
53     sort(a+1,a+n+1,cmp);
54     for(int i=1;i<=n;++i)
55     {
56         if(a[i].s==a[tot].s&&a[i].c==a[tot].c&&a[i].m==a[tot].m)  a[tot].js++;
57         else  {a[++tot].s=a[i].s;  a[tot].c=a[i].c;  a[tot].m=a[i].m;  a[tot].js=1;}
58     }
59     cdq(1,tot);
60     for(int i=1;i<=tot;++i)  ans[a[i].sum+a[i].js-1]+=a[i].js;
61     for(int i=0;i<n;++i)  printf("%d
",ans[i]);
62     return 0;
63 }
一定写对树状数组
原文地址:https://www.cnblogs.com/hzjuruo/p/11269247.html