zoukankan      html  css  js  c++  java
  • 打开CDQ的大门&BZOJ3262

    题目传送门

    第一次接触CDQ分治,感谢YZ大佬的教导。

    CDQ分治就是一种奇特的分治方法,它用左区间的区间信息来更新右区间。

    设CDQ(L,R,l,r)表示递归到区间[L,R],区间的值为[l,r]。

    mid=l+r/2。

    将L~R区间按<=mid和>mid的两块重新分开。

    继续递归区间分治。

    CDQ分治用于解决一类偏序问题,题目中所求的为三维偏序。

    即计算一类ai<bi,aj<bj,ak<bk的贡献。

    普通的二维偏序大家都做过,经典题目逆序对。

    三维怎么做呢?

    第一维依然是SORT,第三位是树状数组。

    第二维是CDQ。

    第一维SORT后有序,故无需考虑第一维。

    第二维CDQ分治时枚举L~R区间,当a[i].y>mid时,计算在权值树状数组上的贡献,否则插入树状数组。

    注意:这道题需要对重复区间判重,否则贡献值不好算。

    code:

    /**************************************************************
        Problem: 3262
        User: yekehe
        Language: C++
        Result: Accepted
        Time:1116 ms
        Memory:10600 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <algorithm>
    using namespace std;
     
    char tc()
    {
        static char tr[10000],*A=tr,*B=tr;
        return A==B&&(B=(A=tr)+fread(tr,1,10000,stdin),A==B)?EOF:*A++;
    }
     
    int read()
    {
        char c;while(c=tc(),c<'0'||c>'9');
        int x=c-'0';while(c=tc(),c>='0'&&c<='9')x=x*10+c-'0';
        return x;
    }
     
    struct node{
        int x,y,z,o;
    }a[100005],lx[100005],rx[100005],Ne[100005];
    int N,K,cnt;
    int at[200005],b[200005],tim,ans[200005],tot[200005];
    inline int cmp(node x,node y){return x.x<y.x || x.x==y.x&&x.y<y.y || x.x==y.x&&x.y==y.y&&x.z<y.z;}
     
    void add(int x,int y)
    {
        for(int i=x;i<=K;i+=i&-i){
            if(b[i]!=tim)at[i]=0,b[i]=tim;
            at[i]+=y;
        }
        return ;
    }
     
    int get(int x)
    {
        int tot=0;
        for(int i=x;i;i-=i&-i)
            if(!(b[i]^tim))tot+=at[i];
        return tot;
    }
     
    void cdq(int L,int R,int l,int r)
    {
        tim++;
        int mid=l+r>>1,lt=0,rt=0;
            for(int i=L;i<=R;i++){
                if(!(l^r)){
                    ans[Ne[i].o]+=get(Ne[i].z);
                    add(Ne[i].z,tot[Ne[i].o]);
                }
                else{
                    if(Ne[i].y<=mid)add(Ne[i].z,tot[Ne[i].o]);
                    else ans[Ne[i].o]+=get(Ne[i].z);
                }
            }//统计贡献
            for(int i=L;i<=R;i++){
                if(Ne[i].y<=mid)lx[++lt]=Ne[i];
                else rx[++rt]=Ne[i];
            }
            for(int i=1;i<=lt;i++)Ne[L+i-1]=lx[i];
            for(int i=1;i<=rt;i++)Ne[L+i-1+lt]=rx[i];//类似于归并那样重组
        if(!(l^r))return ;
        cdq(L,L+lt-1,l,mid);
        cdq(L+lt,R,mid+1,r);
        return ;
    }
     
    int IS(int x,int y){
        return a[x].x==a[y].x&&a[x].y==a[y].y&&a[x].z==a[y].z;
    }
     
    int res[100005];
     
    int main()
    {
        N=read(),K=read();
            for(int i=1;i<=N;i++){
                a[i].x=read(),a[i].y=read(),a[i].z=read();
            }
        sort(a+1,a+N+1,cmp);
        a[0].x=a[0].y=a[0].z=-2e9;
            for(int i=1;i<=N;i++){
                if(IS(i,i-1))++tot[cnt];
                else tot[++cnt]=1,Ne[cnt]=a[i],Ne[cnt].o=cnt;
            }//去重
        cdq(1,cnt,0,K);//注意为cnt
            for(int i=1;i<=cnt;i++)res[ans[i]+tot[i]-1]+=tot[i];
            for(int i=0;i<N;i++)printf("%d
    ",res[i]);
        return 0;
    }
  • 相关阅读:
    (Lineup the Dominoes筛子)三维状压
    Halloween Costumes 玄学题
    jQuery之动画
    javascript之位置
    javascript之事件
    jQuery之DOM
    jQuery之选择器
    jQuery简介
    javascript之Bom简介
    javascript之DOM操作
  • 原文地址:https://www.cnblogs.com/Cptraser/p/8709062.html
Copyright © 2011-2022 走看看