bzoj 3263 陌上花开(cdq分治)

 

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

Sample Output

3
1
3
0
1
0
1
0
0
1

HINT

1 <= N <= 100,000, 1 <= K <= 200,000

 

【思路】

 

    cdq分治

    借网上一句话:第一维排序,第二维cdq分治,第三维树状数组维护。

    首先合并三维都是相同的项。

    先按照第一维排序,然后cdq分治。

    定义solve(l,r)为解决区间l,r内所有询问且solve结束后区间有序,设mid=(l+r)/2,

  1)  Solve(l,mid)

  2)  Solve(mid+1,r)

  3)  处理跨立影响。因为已经排过序,所以左区间的a都要小于右区间的a,因为solve后区间有序,所以左右区间都各自按照b排好了序。按照归并排序的思路,计算左区间对每一个右区间内点的贡献:处理到右区间的l2时,将所有左区间内比他的b小的加入BIT,这时候只要查询一次就可以得出左区间对l2的贡献。

  4)  清理BIT,并按照b c大小将左右区间合并使区间有序

  最后根据题目要求转化一下。

  总的时间为O(nlog^2n),bingo

 

【代码】

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 3*1e5+10;
 8 
 9 struct Node {
10     int a,b,c,s,ans;
11 }que[N],a[N];
12 
13 bool cmp1(const Node& x,const Node& y) {
14     return x.b<y.b||(x.b==y.b&&x.c<y.c);
15 }
16 bool cmp2(const Node& x,const Node& y) {
17     if(x.a==y.a&&x.b==y.b) return x.c<y.c;
18     else if(x.a==y.a) return x.b<y.b;
19     else return x.a<y.a;
20 }
21 
22 int n,K,C[N],ans[N];
23 
24 void add(int x,int v)
25 {
26     for(;x<=K;x+=x&-x) C[x]+=v;
27 }
28 int query(int x)
29 {
30     int res=0;
31     for(;x;x-=x&-x) res+=C[x];
32     return res;
33 }
34 Node t[N];
35 void solve(int l,int r)
36 {
37     if(l==r) return ;
38     int mid=(l+r)>>1;
39     solve(l,mid) , solve(mid+1,r);
40     int l1=l,l2=mid+1;
41     while(l2<=r) {
42         while(l1<=mid && que[l1].b<=que[l2].b) {
43             add(que[l1].c,que[l1].s);
44             l1++;
45         }
46         que[l2].ans+=query(que[l2].c);
47         l2++;
48     }
49     for(int i=l;i<l1;i++)
50         add(que[i].c,-que[i].s);
51     l1=l,l2=mid+1; int pos=l;
52     while(l1<=mid||l2<=r) {
53         if(l2>r||(l1<=mid&&cmp1(que[l1],que[l2]))) t[pos++]=que[l1++];
54         else t[pos++]=que[l2++];
55     }
56     for(int i=l;i<=r;i++) que[i]=t[i];
57 }
58 void read(int& x)
59 {
60     char c=getchar(); x=0;
61     while(!isdigit(c)) c=getchar();
62     while(isdigit(c)) x=x*10+c-'0',c=getchar();
63 }
64 int main()
65 {
66     //freopen("in.in","r",stdin);
67     //freopen("out.out","w",stdout);
68     read(n),read(K);
69     for(int i=1;i<=n;i++)
70         read(a[i].a),read(a[i].b),read(a[i].c);
71     sort(a+1,a+n+1,cmp2);
72     int cnt=0,sz=0;
73     for(int i=1;i<=n;i++) {
74         cnt++;
75         if(a[i].a!=a[i+1].a||a[i].b!=a[i+1].b||a[i].c!=a[i+1].c)
76         {
77             que[++sz]=a[i];
78             que[sz].s=cnt;
79             cnt=0;
80         }
81     }
82     solve(1,sz);
83     for(int i=1;i<=sz;i++)
84         ans[que[i].ans+que[i].s-1]+=que[i].s;
85     //评级为0~n-1的每级花的数量
86     for(int i=0;i<n;i++)
87         printf("%d\n",ans[i]);
88     return 0;
89 }

 

你可能感兴趣的:(bzoj 3263 陌上花开(cdq分治))