[学习笔记]CDQ分治
分治,考虑前一半对后一半的影响。
(和一般分治不太相同的思想是,一般分治不分谁对谁的影响,跨mid的都要统计。(全局变量统计)
而CDQ貌似要落脚到前一半对后一半的影响上,也就是贡献在后一半统计,由前一半产生。
)
大概使用情况:
1.三维偏序
2.优化DP
3.???
例题
[学习笔记]多维偏序
这个里面有。
注意处理三维情况的巧妙性。
CDQ三维偏序优化DP
(树套树也没问题)
注意的是,先divi(l,mid)再统计(l,r)再递归divi(mid+1,r)
因为必须统计贡献有先后了。否则显然有后效性。。
矩阵查询,前缀差分。
然后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 */