• 洛谷 P3810 【模板】三维偏序(陌上花开) (cdq分治模板)


    在solve(L,R)中,需要先分治solve两个子区间,再计算左边区间修改对右边区间询问的贡献。

    注意,计算额外的贡献时,两子区间各自内部的顺序变得不再重要(不管怎么样左边区间的都发生在右边之前),于是就少了一维


    https://www.lydsy.com/JudgeOnline/problem.php?id=3262

    https://www.luogu.org/problemnew/show/P3810

    此题每个操作既是修改又是查询

    对于此题,先按一维排序,在solve(L,R)中先solve两个子区间,然后把L到R的操作按二维排序(由于cdq分治类似归并的特性此时两个子区间内部二维都是有序的,可以直接二路归并),然后就是一个对二、三维求逆序对的过程(只不过只有归并前在第一个区间内的修改生效,归并前在第二个区间内的查询要更新答案)

    可以记一下每个元素在按第一维排序后的编号(以下代码中q[i].num),来判断它归并前是哪个区间里的

    注意:此题第一维相同的实际并不存在顺序关系,理应同时处理然后同时计算贡献,但排序后它们间总是要存在一个特定顺序的,所以要加一些奇怪的特判

    具体的话:首先一开始排序的时候三个关键字都要依次考虑(而不是只考虑第一维),这样可以保证排序后大部分情况下后面的不会对前面产生贡献

    上面还漏考虑了完全相等的三元组,如果它们存在则后面也会对前面产生贡献。因此只要在开始solve前补上这些后面对前面产生的贡献即可

    归并可以简化为

    merge(q+lp,q+mid+1,q+mid+1,q+rp+1,tmp+lp);
    copy(tmp+lp,tmp+rp+1,q+lp);

    inplace_merge(q+lp,q+mid+1,q+rp+1);
     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 struct Q
     5 {
     6     int a,b,c,ans,num;
     7 }q[100100],tmp[100100];
     8 int n,k;
     9 bool c1(const Q &a,const Q &b)    {return a.a<b.a||(a.a==b.a&&a.b<b.b)||(a.a==b.a&&a.b==b.b&&a.c<b.c);}
    10 bool operator<(const Q &a,const Q &b)    {return a.b<b.b||(a.b==b.b&&a.num<b.num);}
    11 bool operator==(const Q &a,const Q &b)    {return a.a==b.a&&a.b==b.b&&a.c==b.c;}
    12 int dat[200100];
    13 const int N=200000;
    14 #define lowbit(x) ((x)&(-x))
    15 void addx(int pos,int d)
    16 {
    17     for(;pos<=N;pos+=lowbit(pos))    dat[pos]+=d;
    18 }
    19 int sum(int pos)
    20 {
    21     int ans=0;
    22     for(;pos>0;pos-=lowbit(pos))    ans+=dat[pos];
    23     return ans;
    24 }
    25 int num[100100];
    26 void solve(int lp,int rp)
    27 {
    28     if(lp==rp)    return;
    29     int mid=lp+(rp-lp)/2;
    30     solve(lp,mid);solve(mid+1,rp);
    31     int k=lp-1,i,j;
    32     for(i=lp,j=mid+1;i<=mid&&j<=rp;)
    33     {
    34         ++k;
    35         if(q[i]<q[j])    tmp[k]=q[i++];
    36         else    tmp[k]=q[j++];
    37     }
    38     while(i<=mid)    tmp[++k]=q[i++];
    39     while(j<=rp)    tmp[++k]=q[j++];
    40     for(i=lp;i<=rp;i++)    q[i]=tmp[i];
    41     for(i=lp;i<=rp;i++)
    42     {
    43         if(q[i].num<=mid)    addx(q[i].c,1);
    44         else    q[i].ans+=sum(q[i].c);
    45     }
    46     for(i=lp;i<=rp;i++)
    47         if(q[i].num<=mid)
    48             addx(q[i].c,-1);
    49 }
    50 int main()
    51 {
    52     int i,j,t,tt=0;
    53     scanf("%d%d",&n,&t);
    54     for(i=1;i<=n;i++)    scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c);
    55     sort(q+1,q+n+1,c1);
    56     for(i=1;i<=n;i++)
    57     {
    58         tt++;
    59         if(i==n||!(q[i]==q[i+1]))
    60         {
    61             for(j=i-tt+1,t=tt-1;j<=i;j++)    q[j].ans+=t,--t;
    62             tt=0;
    63         }
    64     }
    65     for(i=1;i<=n;i++)    q[i].num=i;
    66     solve(1,n);
    67     for(i=1;i<=n;i++)    num[q[i].ans]++;
    68     for(i=0;i<n;i++)    printf("%d
    ",num[i]);
    69     return 0;
    70 }

    来看看cdq分治的限制

    1.题目允许离线操作
    2.修改操作对询问的贡献独立,且修改之间互不影响
    3.修改对答案的贡献是确定的,与判定标准无关

  • 相关阅读:
    NYOJ题目28大数阶乘
    网页小图标设置
    Sass中文乱码问题(手动编译和watch编译)
    设计模式之构建者模式(Builder):初步理解
    Struts2之类型转换器
    css设置网页文本选中样式
    由超市临时储物柜引发的一点设计随想...
    前端资源相关参考资料
    Struts2拦截器之ExceptionMappingInterceptor(异常映射拦截器)
    Struts2之OGNL
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9028492.html
Copyright © 2020-2023  润新知