• 【BZOJ3262】陌上花开 (CDQ分治+树状数组+排序)


     

    Time Limit: 3000 ms   Memory Limit: 256 MB

    Description

      有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。

      现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。

      定义一朵花A比另一朵花B要美丽,当且仅当 $S_a ge S_b, C_a ge C_b, M_a ge M_b$

      显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

    Input

      第一行为 N,K 分别表示花的数量和最大属性值。
      以下 N 行,每行三个整数 $s_i , c_i , m_i$  表示第i朵花的属性。

    Output

      包含 $N$ 行,分别表示评级为 $0…N−1$ 的每级花的数量。

     

    
    

    Sample Input

    Sample Output

    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


    
    

    题解

      题目大意为,给定n个三元组,每个三元组的等级为小于等于它的三元组的个数。

        其中“小于”定义为:对于两个三元组$A(s1,c1,m1)$与$B(s2,c2,m2)$,$A le B$当且仅当$s_1 le s_2$且$c_1 le c_2$

    且$m_1 le b_2$。

       

      隐隐约约想到单调性的问题。

      1. 对于$s$,我们直接排序处理(按照$s$第一,$c$第二,$m$第三的优先级排序);

      2. 对于$c$,开始使用CDQ分治瞎搞(其中每次回溯的时候分别对左右区间,以$c$为第一关键字排序,为计算左区间对右区间的贡献作准备);  

      3. 对于$m$:我们在CDQ分治时,已经确定左半边区间的$s$是小于右半边区间的;这时采用双指针扫描,以右区间指针指向的三元组为基准三元组。考虑此时 $c$ 是递增的,我们就将左区间的指针移到最靠右的三元组,使得这个三元组的$c$值不超过基准三元组的$c$值;

        其中,我们一边扫描左区间一边将左区间扫过的三元组的$m$值丢进树状数组里,左指针到基准时,直接询问树状数组内小于等于与基准三元组的$m$值。

      

      完全相同的几朵花怎么办? 我们按照上面提到的排序方法排序所有花,对于相同的花,将它们的等级都标记为相同花的中等级最高的即可。

      


     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 const int N=1e5+10,K=2e5+10;
     5 int n,k,ans[N];
     6 struct Flower{int s,c,m,sum;}f[N];
     7 struct Bit{
     8     int arr[K],lis[N],cnt;
     9     void reset(){
    10         for(;cnt;cnt--) add(lis[cnt],-1,1);
    11     }
    12     void add(int u,int num,int flag){
    13         if(!u) return;
    14         if(!flag)
    15             lis[++cnt]=u;
    16         for(;u<=k;u+=u&-u) arr[u]+=num;
    17     }
    18     int que(int u){
    19         int ret=0;
    20         for(;u;u-=u&-u) ret+=arr[u];
    21         return ret;
    22     }
    23 }bit;
    24 bool cmpAll(Flower x,Flower y){
    25     if(x.s!=y.s) return x.s<y.s;
    26     if(x.c!=y.c) return x.c<y.c;
    27     return x.m<y.m;
    28 }
    29 bool cmpC(Flower x,Flower y){return x.c<y.c;}
    30 void cdq(int l,int r){
    31     if(l==r) return;
    32     int mid=(l+r)/2;
    33     cdq(l,mid);
    34     cdq(mid+1,r);
    35     sort(f+l,f+mid+1,cmpC);
    36     sort(f+mid+1,f+r+1,cmpC);
    37     int i=l,j;
    38     bit.reset();        
    39     for(i=l,j=mid+1;j<=r;j++){
    40         while(i<=mid&&f[i].c<=f[j].c){
    41             bit.add(f[i].m,1,0);
    42             i++;
    43         }
    44         f[j].sum+=bit.que(f[j].m);    
    45     }
    46 }
    47 int main(){
    48     scanf("%d%d",&n,&k);    
    49     for(int i=1;i<=n;i++)
    50         scanf("%d%d%d",&f[i].s,&f[i].c,&f[i].m);
    51     sort(f+1,f+1+n,cmpAll);
    52     cdq(1,n);
    53     sort(f+1,f+1+n,cmpAll);
    54     for(int i=1;i<=n;){
    55         int j=i,maxs=0;
    56         while(f[i].s==f[j].s&&f[i].c==f[j].c&&f[i].m==f[j].m){
    57             maxs=max(maxs,f[j].sum);
    58             j++;
    59         }
    60         ans[maxs]+=j-i;
    61         i=j;
    62     }
    63     for(int i=0;i<=n-1;i++)
    64         printf("%d
    ",ans[i]);
    65     return 0;
    66 }
    神奇代码
  • 相关阅读:
    Oracle、Microsoft SQL Server、Mysql
    判断窗口是否最大化或者最小化
    获得桌面长宽
    Cmap的使用
    获取本地IP,并设置到IP控件
    定时器
    %
    ThinkPHP3.2.3 的异常和错误屏蔽处理
    大数据助银行提高征信水平和风险监控能力
    大数据助银行提高征信水平和风险监控能力
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/7375958.html
Copyright © 2020-2023  润新知