zoukankan      html  css  js  c++  java
  • 【高级数据结构】cdq分治(陌上花开·三维偏序)

    【高级数据结构】cdq分治(陌上花开·三维偏序)

    一、陌上花开

    题目链接:陌上花开

    对于这道题我们需要求三维偏序中每个元素比其小的元素个数

    • 我们先对数组进行排序,$x$ 为第一关键字,$y$ 为第二关键字,$z$ 为第三关键字,从小到大排序
     1 struct Point{
     2     int x,y,z,ans,num;
     3     bool operator < (const Point &rhs) const
     4     {
     5         return x!=rhs.x?x<rhs.x:(y!=rhs.y?y<rhs.y:z<rhs.z);
     6     }
     7     bool operator != (const Point &rhs) const
     8     {
     9         return x!=rhs.x||y!=rhs.y||z!=rhs.z;
    10     }
    11 }A[MAXN],a[MAXN],b[MAXN];
    • 然后是去重,因为这道题是求带等号的偏序
    1 for (int i=1;i<=n;i++)
    2 {
    3     if (A[i]!=A[i-1]) a[++tot]=A[i];
    4     a[tot].num++;
    5 }
    • 接着就是算法的主题cdq分治部分

    分治的意义是分而治之,将数据规模大的问题分解为若干个规模较小的但解决方法一样的子问题,直到子问题能够在常数时间内解决,大问题的答案有子问题在线性时间内合并而成。

    我们先考虑结束情况,当 $l = r$ 是不会产生贡献,即为结束状态。

    我们在考虑如何合并两个子问题

    由于第一次的排序,我们已经保证 $[l,mid]$ (左)区间的 $x$ 均小于等于 $[mid+1,r]$ (右)区间的 $x$

    我们考虑一般的归并排序思路按 $y$ 合并数组

    在合并的过程中,我们发现已经合并的数组中 $x$ $y$ 的值均小于 $[mid+1,r]$ 区间的 $x$ $y$

    当一个右区间开头的数小于左区间开头的数,该左区间已经合并的数中 $x$ $y$ 都小于右区间的开头的 $x$ $y$,所以我们只要维护已合并的左区间中 $z$ 小于右区间开头的 $z$ 的个数即可

    我们选择使用常数优越的树状数组维护。

    时间复杂度 $O(N log^{2} N)$

     1 #include<bits/stdc++.h>
     2 #define MAXK 200010
     3 #define MAXN 100010
     4 using namespace std;
     5 inline int read ()
     6 {
     7     int s=0,w=1;
     8     char ch=getchar ();
     9     while (ch<'0'||ch>'9'){if (ch=='-') w=-1;ch=getchar ();}
    10     while ('0'<=ch&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar ();
    11     return s*w;
    12 }
    13 struct Point{
    14     int x,y,z,ans,num;
    15     bool operator < (const Point &rhs) const
    16     {
    17         return x!=rhs.x?x<rhs.x:(y!=rhs.y?y<rhs.y:z<rhs.z);
    18     }
    19     bool operator != (const Point &rhs) const
    20     {
    21         return x!=rhs.x||y!=rhs.y||z!=rhs.z;
    22     }
    23 }A[MAXN],a[MAXN],b[MAXN];
    24 int n,k,tot;
    25 int c[MAXK],f[MAXN],num[MAXN];
    26 bool used[MAXN];
    27 int lowbit (int x)
    28 {
    29     return x&-x;
    30 }
    31 void add (int x,int val)
    32 {
    33     for (int i=x;i<=k;i+=lowbit (i)) c[i]+=val;
    34 }
    35 int query (int x)
    36 {
    37     int sum=0;
    38     for (int i=x;i>=1;i-=lowbit (i)) sum+=c[i];
    39     return sum;
    40 }
    41 void cdq (int l,int r)
    42 {
    43     if (l==r) return;
    44     int mid=(l+r)>>1;
    45     cdq (l,mid),cdq (mid+1,r);
    46     int i=l,j=mid+1;
    47     for (int k=l;k<=r;k++)
    48     {
    49         if (a[i].y<=a[j].y&&i<=mid)
    50         {
    51             add (a[i].z,a[i].num);
    52             b[k]=a[i++];
    53             used[k]=1;
    54         }
    55         else if (a[i].y>a[j].y&&j<=r)
    56         {
    57             a[j].ans+=query (a[j].z);
    58             b[k]=a[j++];
    59         }
    60         else if (i>mid)
    61         {
    62             a[j].ans+=query (a[j].z);
    63             b[k]=a[j++];
    64         }
    65         else b[k]=a[i++];
    66     }
    67     for (int i=l;i<=r;i++) a[i]=b[i];
    68     for (int i=l;i<=r;i++)
    69         if (used[i]) add (a[i].z,-a[i].num),used[i]=0; 
    70 }
    71 int main()
    72 {
    73     n=read ();k=read ();
    74     for (int i=1;i<=n;i++) A[i].x=read (),A[i].y=read (),A[i].z=read ();
    75     sort (A+1,A+n+1);
    76     for (int i=1;i<=n;i++)
    77     {
    78         if (A[i]!=A[i-1]) a[++tot]=A[i];
    79         a[tot].num++;
    80     }
    81     cdq (1,tot);
    82     for (int i=1;i<=n;i++) f[a[i].ans+a[i].num-1]+=a[i].num;
    83     for (int i=0;i<n;i++) printf ("%d
    ",f[i]);
    84     return 0;
    85 }
  • 相关阅读:
    MFC和Qt优缺点 (MFC几乎没有优点、全面下风)
    获得WIN7管理员权限(可通过修改注册表,或者组策略改变)
    tolua#是Unity静态绑定lua的一个解决方案
    C#实现拼图游戏
    FastDFS分布式文件系统
    生成动态Lambda表达式1
    Azure IoT
    SignalR
    延迟队列功能
    监控知识体系
  • 原文地址:https://www.cnblogs.com/PaulShi/p/10076780.html
Copyright © 2011-2022 走看看