• BZOJ 2989: 数列/4170: 极光


    题解:

    n倍经验题

    首先比较容易想到的是对绝对值分类讨论

    然后是4维偏序

    1.查询和修改顺序

    2.x>y

    3.a[x]>a[y]

    4.(x+a[x])-(y+a[y])<=k

    这样是nlogn^3的,也许可以卡过吧。。。

    另外注意在解决偏序问题的时候我们尽量使用cdq分治嵌套

    注意cdq分治嵌套的时候

    合并用归并排序这样才是nlog^3不然是nlog^4的

    如果每层都要用归并的话每层要用不同数组

    由于前面不对复杂度造成影响所以其实直接最后一层用归并就可以了

    #include <bits/stdc++.h>
    using namespace std;
    #define IL inline
    #define rint register int
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    char ss[1<<24],*A=ss,*B=ss;
    char gc()
    {
      return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; 
    }
    template<class T>void read(T &x)
    {
      rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=c^48;
      while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
    }
    const int INF=1e9;
    const int N=2e5+10;
    struct re{
      int a,b,c,d,e,f,g;
    }a[N],b[N];
    int ans[N];
    IL bool cmp(re x,re y)
    {
      return(x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c));
    }
    IL bool cmp2(re x,re y)
    {
      return(x.b<y.b||(x.b==y.b&&x.c<y.c)||(x.b==y.b&&x.c==y.c&&x.a<y.a));
    }
    IL bool cmp3(re x,re y)
    {
      return(x.c<y.c||(x.c==y.c&&x.a<y.a)||(x.c==y.c&&x.a==y.a&&x.b<y.b));
    }
    #define mid ((h+t)/2)
    IL void cdq_fz2(int h,int t)
    {
      if (h==t) return;
      cdq_fz2(h,mid); cdq_fz2(mid+1,t);
      rep(i,h,mid) a[i].f=1;
      rep(i,mid+1,t) a[i].f=0;
      int h1=h,h2=mid+1,h3=h;
      while (h1<=mid&&h2<=t)
        if (cmp3(a[h1],a[h2])) b[h3++]=a[h1++];
        else b[h3++]=a[h2++];
      while (h1<=mid) b[h3++]=a[h1++];
      while (h2<=t) b[h3++]=a[h2++];
      rep(i,h,t) a[i]=b[i];
      int cnt=0;
      rep(i,h,t)
      {
        if (a[i].e&a[i].f) cnt+=a[i].d;
        if (!(a[i].e|a[i].f)) a[i].g+=cnt;
      }
    }
    IL void cdq_fz1(int h,int t)
    {
      if (h==t) return;
      cdq_fz1(h,mid); cdq_fz1(mid+1,t);
      rep(i,h,mid) a[i].e=1;
      rep(i,mid+1,t) a[i].e=0;
      sort(a+h,a+t+1,cmp2);
      cdq_fz2(h,t);
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      int n,k;
      read(n); read(k); int nn=n;
      rep(i,1,n) read(a[i].a),read(a[i].b),read(a[i].c),a[i].d=1;
      sort(a+1,a+n+1,cmp);
      int l=0;
      a[0].a=INF;
      rep(i,1,n)
       if (a[i].a==a[i-1].a&&a[i].b==a[i-1].b&&a[i].c==a[i-1].c)
         a[l].d++; else a[++l]=a[i];
      n=l;
      cdq_fz1(1,n);
      for(int i=1;i<=n;i++) ans[a[i].g+a[i].d-1]+=a[i].d;
      for (int i=0;i<=nn-1;i++) cout<<ans[i]<<endl;
      return 0;
    }

    避免使用树套树

    因为这样能大量降低编程复杂度

    另外一种比较简单的方法是

    当我们解不等式abs(x-y)+abs(a[x]-a[y])<=k时

    先利用绝对值不等式abs(x-y+a[x]-a[y])<=abs(x-y)+abs(a[x]-a[y])<=k

    得出-k<=x-y+a[x]-a[y]<=k(我并没有想出来这样为什么是等效的)

    那么加上查询和修改顺序是三维偏序

    正解是把它放到二维平面上

    然后由于是一个菱形

    将笛卡尔坐标旋转45°

    然后三维偏序的cdq做法或者kd-tree就都可以了

    另外本题如果强制在线除了kd-tree还有一种做法

    就是二进制分组

  • 相关阅读:
    Ztree下拉框多选
    FullCalendar日程插件
    viscose 前端常用插件
    一些词
    关于require()和export引入依赖的区别
    关于CMD/AMD和Common.js/Sea.js/Require.js
    vue中的双向数据绑定原理简单理解
    Vue-cli简单使用
    webpack简单配置
    vuex基础
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9288925.html
Copyright © 2020-2023  润新知