CDQ分治的用途
- 我们可能一些问题,每个状态和操作有先后的关系(即
i
的信息要从[1,i−1]转移或者调用)
- 此时我们可以用CDQ分治以
log
的复杂度来降掉一个维度。
CDQ的基本流程
- 对于[1,8]这一个需要从小到大操作的区间我们可以给它造一个树
- 之后我们按先序遍历依次地遍历并更新答案
void CDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1;
CDQ(l,mid);
clear();
insert(L,mid);
Query(mid+1,R);
CDQ(mid+1,r);
}
例题
二维LIS
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int n,m,ans,T[M],dp[M];
struct node{
int v,x,y,id,mx,mi;
bool operator<(const node&A)const{
if(x!=A.x)return x<A.x;
if(y!=A.y)return y<A.y;
return id<A.id;
}
}A[M],B[M];
inline void Max(int&a,int b){if(a<b)a=b;}
inline void Min(int&a,int b){if(a>b)a=b;}
inline void add(int x,int v){
for(;x<M;x+=x&-x){
if(v)Max(T[x],v);
else T[x]=0;
}
}
inline int MAX(int x){
int res=0;
for(;x;x-=x&-x)Max(res,T[x]);
return res;
}
void CDQ(int l,int r){
if(l==r){
Max(dp[l],1);
return;
}int mid=l+r>>1;
CDQ(l,mid);
for(int i=l;i<=r;i++){
B[i].id=i;
if(i<=mid)B[i].x=A[i].v,B[i].y=A[i].mx;
else B[i].x=A[i].mi,B[i].y=A[i].v;
}sort(B+l,B+r+1);
for(int i=l;i<=r;i++){
if(B[i].id<=mid)add(B[i].y,dp[B[i].id]);
else Max(dp[B[i].id],MAX(B[i].y)+1);
}
for(int i=l;i<=r;i++)add(B[i].y,0);
CDQ(mid+1,r);
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&A[i].v),A[i].mx=A[i].mi=A[i].v;
for(int i=1,x,y;i<=m;++i){
scanf("%d %d",&x,&y);
Max(A[x].mx,y);
Min(A[x].mi,y);
}
CDQ(1,n);
for(int i=1;i<=n;++i)Max(ans,dp[i]);
printf("%d",ans);
return 0;
}
皇后大道东
dp[1][1]=1;
For(i,1,n-1){
int res=0;
memset(cnt,0,sizeof(cnt));
For(j,1,m-1){
For(k,1,i){//更新黄色的区间
int c=col[k][j];
Add(res,dp[k][j]);
Add(cnt[c],dp[k][j]);
}//用它来更新橙色的块的dp值
int c=col[i+1][j+1];
Add(dp[i+1][j+1],res);
Mis(dp[i+1][j+1],cnt[c]);
}
}ptn(dp[n][m]);
- 我们发现因为这里的
i
行的信息要都是从[1,i−1]行的转移过来的,于是我们可以使用
CDQ
了。
void BDQ(int l,int r){
if(l==r)return;
int mid=l+r>>1,res=0;
BDQ(l,mid);
For(j,1,m){
/*此时我们已经把第[l,mid]行第[j-1]列的信息都处理出来了,直接转移到橙色*/
For(i,mid+1,r)Add(dp[i][j],res),Mis(dp[i][j],cnt[col[i][j]]);
/*再把第[l,mid]行第[j]列的信息加过来,更新黄色的*/
For(i,l,mid)Add(res,dp[i][j]),Add(cnt[col[i][j]],dp[i][j]);
}
For(i,l,r)For(j,1,m)cnt[col[i][j]]=0;
BDQ(mid+1,r);
}