zoukankan      html  css  js  c++  java
  • Luogu P3810 【模板】三维偏序(陌上花开)(CDQ分治)

    题目
    以三维偏序为例来讲一下CDQ分治。
    CDQ的本质就是把一个序列分成两段,计算左边对右边的贡献,然后分治。
    不过一般都是先分治到底再从下往上算,这样可以先归并再算。
    比如这道题,我们先按第一维排序,然后分治完下一层之后边归并排序边算贡献。
    具体大概是这样:
    比如我们已经把下面的全部算完了,那么传上来的左边和有边一定满足:
    1、左边的第一维都比右边的第一维小。
    2、左边和右边在第二维上都是升序的。
    那么我们归并排序,遇到左边的就加入数据结构修改贡献,遇到右边的就计算贡献。
    同时我们能够保证传上去的是在第二维上是升序的。
    在这一题的话,因为我们满足左边的第一维都比右边的小,两边的第二维都是升序,所以我们在归并的过程中只要对每个右边的计算前面的左边的第三维比它小的个数。这个可以通过离散化+去重+BIT维护桶解决。
    跟整体二分一样,最后的清零要用撤销而不是memset,否则复杂度bomb。

    #include<bits/stdc++.h>
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
        void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
    ');}
    }
    using namespace IO;
    const int N=100007,M=N<<1;
    int k,p[N],q[N],a[N],b[N],c[N],t[M],v[N],cnt[N],ans[N];
    int cmp(int x,int y){return a[x]<a[y]||(a[x]==a[y]&&(b[x]<b[y]||(b[x]==b[y]&&c[x]<c[y])));}
    void modify(int i,int v){for(;i<=k;i+=i&-i)t[i]+=v;}
    int query(int i){int sum=0;for(;i;i-=i&-i)sum+=t[i];return sum;}
    void cdq(int *p,int n)
    {
        if(n==1) return;
        int m=n>>1,i,j,k,x,y;
        for(cdq(p,m),cdq(p+m,n-m),memcpy(q,p,n<<2),k=i=0,j=m;i<m&&j<n;++k)
        {
    	x=q[i],y=q[j];
    	if(b[x]<=b[y]) modify(c[p[k]=x],v[x]),++i; else cnt[y]+=query(c[p[k]=y]),++j;
        }
        for(;j<n;++j) cnt[q[j]]+=query(c[q[j]]);
        for(memcpy(p+k,q+i,(m-i)<<2),--i;~i;--i) modify(c[q[i]],-v[q[i]]);
    }
    int main()
    {
        int n=read(),i,j,x,y;
        for(k=read(),i=0;i<n;++i) p[i]=i,a[i]=read(),b[i]=read(),c[i]=read();
        for(sort(p,p+n,cmp),i=1,j=0;i<n;++i)
        {
    	x=p[i],y=p[j],++v[y];
    	if(a[x]^a[y]||b[x]^b[y]||c[x]^c[y]) p[++j]=x;
        }
        ++v[p[j++]],cdq(p,j);
        for(i=0;i<j;++i) ans[cnt[p[i]]+v[p[i]]-1]+=v[p[i]];
        for(i=0;i<n;++i) write(ans[i]);
        return Flush(),0;
    }
    
  • 相关阅读:
    如何通过命令行窗口查看sqlite数据库文件
    eclipse自动补全的设置
    文本装饰
    注释和特殊符号
    文本装饰
    网页背景
    通过ArcGIS Server admin 查看和删除已注册的 Web Adaptor
    通过 ArcGIS Server Manager 查看已安装的 Web Adaptor
    通过 ArcGIS Server Manager 验证 DataStore
    Windows上安装ArcGIS Enterprise——以 Windows Server 2012 R2上安装 ArcGIS 10.8为例
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11938390.html
Copyright © 2011-2022 走看看