• 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;
    }
    
  • 相关阅读:
    MyEclipse去除网上复制下来的代码带有的行号
    Python人工智能第二篇
    Celery
    SQLAlchemy介绍
    MongoDB
    第三篇 Flask 中的 request
    linux安装
    第二篇 Flask 中的 Render Redirect HttpResponse
    第九篇 Flask 中的蓝图(BluePrint)
    第一篇 Flask
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11938390.html
Copyright © 2020-2023  润新知