zoukankan      html  css  js  c++  java
  • BZOJ3262:陌上花开(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

    Solution

    正好借这个题的题解总结一下我对CDQ的理解
    顺便借这个题学了一下一直没碰过的树状数组……
    首先对于三维偏序$(a,b,c)$,我们可以以a为关键字进行sort,
    这样数组中的a就是有序的,每次分治当前区间我们只考虑左半边对右半边的贡献,这样就可以消除a的影响QAQ
    再观察一下现在要解决的问题,统计$b_{j}<=b_{i}$且$c_{j}<=c[i]$
    如果我们把b当做数组下标,c当数组下标里的值的话,可以想到什么?逆序对!不过这里是个顺序对就是了
    所以就是第一维使其sort有序,第二维分治的时候归并排序使其有序,第三维用树状数组进行统计
    注意要去重,否则如果A=B,那么(A,B)(B,A)本来都是可以的,但分治的时候不去重我们只能考虑进去一种

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #define N (200000+1000)
     6 using namespace std;
     7 
     8 int n,k,emm,top,c[N],ans[N];
     9 
    10 int lowbit(int x){return x&-x;}
    11 int add(int x,int delta){for (; x<=k; x+=lowbit(x)) c[x]+=delta;}
    12 int sum(int x){int sum=0; for (; x; x-=lowbit(x)) sum+=c[x]; return sum;}
    13 
    14 struct Node
    15 {
    16     int a,b,c,size,ans;
    17     bool operator < (const Node &A) const 
    18     {
    19         if (a==A.a && b==A.b) return c<A.c;
    20         if (a==A.a) return b<A.b;
    21         return a<A.a;
    22     }
    23 }a[N],t[N];
    24 
    25 void CDQ(int l,int r)
    26 {
    27     if (l==r) return;
    28     int mid=(l+r)>>1;
    29     CDQ(l,mid); CDQ(mid+1,r);
    30     int i=l,j=mid+1,p=l;
    31     while (i<=mid || j<=r)
    32     {
    33         if (j>r || i<=mid && a[i].b<=a[j].b) add(a[i].c,a[i].size),t[p++]=a[i++];
    34         else a[j].ans+=sum(a[j].c),t[p++]=a[j++];
    35     }
    36     for (int i=l; i<=mid; ++i) add(a[i].c,-a[i].size);
    37     for (int i=l; i<=r; ++i) a[i]=t[i];
    38 }
    39 
    40 int main()
    41 {
    42     scanf("%d%d",&n,&k); emm=n;
    43     for (int i=1; i<=n; ++i)
    44         scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c),a[i].size=1;
    45     sort(a+1,a+n+1);
    46     top=1;
    47     for (int i=2; i<=n; ++i)
    48     {
    49         if (a[i].a==a[top].a && a[i].b==a[top].b && a[i].c==a[top].c)
    50             a[top].size++;
    51         else a[++top]=a[i];
    52     }
    53     n=top;
    54     CDQ(1,n);
    55     for (int i=1; i<=n; ++i) ans[a[i].ans+a[i].size-1]+=a[i].size;
    56     for (int i=0; i<emm; ++i) printf("%d
    ",ans[i]);
    57 }
  • 相关阅读:
    学习进度第七周
    NABCD---生活日历
    学习进度第六周
    人月神话阅读笔记(3)
    人月神话阅读笔记(2)
    人月神话阅读笔记(1)
    石家庄地铁查询(双人项目)
    学习进度第五周
    学习进度第四周
    返回一个整数数组中最大子数组的和。(续2)---二维数组
  • 原文地址:https://www.cnblogs.com/refun/p/9339506.html
Copyright © 2011-2022 走看看