zoukankan      html  css  js  c++  java
  • 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还有一种做法

    就是二进制分组

  • 相关阅读:
    对 Unity 脚本生命周期的调研
    实现僵尸跑酷游戏的 UGUI 实践
    Unity UGUI 按钮绑定事件的 4 种方式
    virtualbox下给centos7固定ip
    linux新建文件夹
    centos7修改hostname
    linux下杀进程的方法
    virtualbox下最小化安装centos7后上网设置
    ubuntu下自动获取ip设置
    Caused by: org.springframework.beans.NotWritablePropertyException:
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9288925.html
Copyright © 2011-2022 走看看