[学习笔记]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\n",a[i].ans);
    }
    return 0;
}

}
int main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/11/23 21:10:32
*/
Mokia 摩基亚

 

posted @ 2018-11-23 20:32  *Miracle*  阅读(182)  评论(0编辑  收藏  举报