• [学习笔记]CDQ分治


    分治,考虑前一半对后一半的影响。

    (和一般分治不太相同的思想是,一般分治不分谁对谁的影响,跨mid的都要统计。(全局变量统计)

    而CDQ貌似要落脚到前一半对后一半的影响上,也就是贡献在后一半统计,由前一半产生。

     

    大概使用情况:

    1.三维偏序

    2.优化DP

    3.???

    例题

    [学习笔记]多维偏序

    这个里面有。

    注意处理三维情况的巧妙性。

    [HEOI2016/TJOI2016]序列

    CDQ三维偏序优化DP

    (树套树也没问题)

    注意的是,先divi(l,mid)再统计(l,r)再递归divi(mid+1,r)

    因为必须统计贡献有先后了。否则显然有后效性。。

    [BOI2007]Mokia 摩基亚

    矩阵查询,前缀差分。

    然后cdq分治,两边按照x排序一下,然后双指针扫描,左半部分的修改,加入权值线段树(权值树状数组)里,然后区间查询统计增加的用户即可。

    可以离散化节省时空。

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define mid ((l+r)>>1)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=200000+5;
    struct node{
        int sum;
    }t[4*N];
    struct que{
        int x,y0,y1;
        int typ;
        int sum;
        int id;
        bool friend operator<(que a,que b){
            return a.x<b.x;
        }
    }q[N];
    int tot;
    struct matrix{
        int ans;
    }a[10000+5];
    int cnt;
    int b[N],c[N],num;
    int mx;
    void pushup(int x){
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
    void add(int x,int l,int r,int to,int c){
        if(l==r){
            t[x].sum+=c;return;
        }
        if(to<=mid) add(x<<1,l,mid,to,c);
        else add(x<<1|1,mid+1,r,to,c);
        pushup(x);
    }
    int query(int x,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            return t[x].sum;
        }
        int ret=0;
        if(L<=mid) ret+=query(x<<1,l,mid,L,R);
        if(mid<R) ret+=query(x<<1|1,mid+1,r,L,R);
        return ret;
    }
    void divi(int l,int r){
        
        if(l==r) return;
        divi(l,mid);divi(mid+1,r);
        //cout<<" l "<<l<<" r "<<r<<endl;
        sort(q+l,q+mid+1);sort(q+mid+1,q+r+1);
        int j=l;
        for(reg i=mid+1;i<=r;++i){
            if(q[i].typ==1) continue;
            while(j<=mid&&(q[j].x<=q[i].x)){
                if(q[j].typ!=1) {
                    ++j;continue;
                }
                add(1,1,num,q[j].y0,q[j].sum);
                ++j;
            }
            q[i].sum+=query(1,1,num,q[i].y0,q[i].y1);
        }
        for(reg i=l;i<j;++i){
            if(q[i].typ!=1) continue;
            add(1,1,num,q[i].y0,-q[i].sum);
        }
    //    for(reg i=1;i<=tot;++i){
    //        cout<<i<<" : "<<q[i].typ<<" "<<q[i].x<<" "<<q[i].sum<<endl;
    //    }
    //    cout<<"sum "<<t[1].sum<<endl;
    }
    int main(){
        int op;
        int x0,x1,y0,y1;
        while(1){
            scanf("%d",&op);
            if(op==3) break;
            else if(op==0){
                scanf("%d",&mx);
            }
            else if(op==1){
                ++tot;
                q[tot].typ=1;
                scanf("%d%d%d",&q[tot].x,&q[tot].y0,&q[tot].sum);
                b[++num]=q[tot].y0;
            }
            else{
                ++cnt;
                ++tot;q[tot].typ=2;q[tot].id=cnt;
                scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
                q[tot].x=x1,q[tot].y0=y0,q[tot].y1=y1;
                b[++num]=q[tot].y0;b[++num]=q[tot].y1;
                
                ++tot;q[tot].typ=3;q[tot].id=cnt;
                q[tot].x=x0-1,q[tot].y0=y0,q[tot].y1=y1;
            }
        }
        sort(b+1,b+num+1);
        num=unique(b+1,b+num+1)-b-1;
        //cout<<" tot "<<tot<<endl;
        for(reg i=1;i<=tot;++i){
            //cout<<" ii "<<i<<" ";
            if(q[i].typ==1){
                q[i].y0=lower_bound(b+1,b+num+1,q[i].y0)-b;
                //cout<<" typ"<<q[i].typ<<" "<<q[i].y0<<endl;
            }
            else{
                q[i].y0=lower_bound(b+1,b+num+1,q[i].y0)-b;
                q[i].y1=lower_bound(b+1,b+num+1,q[i].y1)-b;
                //cout<<" typ"<<q[i].typ<<" "<<q[i].y0<<" "<<q[i].y1<<endl;
            }
        }
        divi(1,tot);
        for(reg i=1;i<=tot;++i){
            if(q[i].typ==2){
                a[q[i].id].ans+=q[i].sum;
            }else if(q[i].typ==3){
                a[q[i].id].ans-=q[i].sum;
            }
        }
        for(reg i=1;i<=cnt;++i){
            printf("%d
    ",a[i].ans);
        }
        return 0;
    }
    
    }
    int main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/11/23 21:10:32
    */
    Mokia 摩基亚
  • 相关阅读:
    思源黑体、思源宋体的 TTF 版本
    MySQL Workbench导入/导出SQL文件的方法
    高精度计算器
    树的直径和重心
    linux 分区 和 硬盘分区的对应关系
    layer 子页面传值给父页面
    php复制文件夹所有文件
    php删除文件夹下所有的文件夹和文件
    PHP将多级目录打包成zip文件
    云原生应用开发“12Factors”
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10009615.html
Copyright © 2020-2023  润新知