CDQ分治

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CDQ分治相关的知识,希望对你有一定的参考价值。

CDQ分治

偏序类

二维偏序

对一维排序,然后另一维BIT维护即可。

HDU 1541

// Problem: Stars
// Contest: HDOJ
// URL: https://acm.hdu.edu.cn/showproblem.php?pid=1541
// Memory Limit: 65 MB
// Time Limit: 2000 ms
// Date: 2021-07-28 16:55:09
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e4+5,M=32005,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int n;
struct BIT{
	#define lowbit(x) x&(-x)
	#define il inline
	ll s[M];
	il void upd(int x,int v){
		while(x<M){
			s[x]+=v;x+=lowbit(x);
		}return;
	}
	il ll que(int x){
		ll ans=0;
		while(x){
			ans+=s[x];x-=lowbit(x);
		}return ans;
	}
}T;
int b[N];
int main(){
	while(~scanf("%d",&n)){
	mst(b,0);mst(T.s,0);
	for(int i=1,x,y;i<=n;i++){
		scanf("%d%d",&x,&y);
		b[T.que(x+1)]++;
		T.upd(x+1,1);
	}
	for(int i=0;i<n;i++) printf("%d\\n",b[i]);
	}
	return 0;
}

三维偏序

一维排序,二维分治,三维BIT。

// Problem: P3810 【模板】三维偏序(陌上花开)
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3810
// Memory Limit: 500 MB
// Time Limit: 1000 ms
// Date: 2021-07-28 18:47:45
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
//if have char input #define should cancel
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline T& read(T& r) {
    r = 0; bool w = 0; char ch = getchar();
    while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
    while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
    return r = w ? -r : r;
}
struct node{
	int x,y,z,v,c;
}a[N],b[N];
inline bool cmp1(node &a,node &b){	//按一维排序
	if(a.x!=b.x) return a.x<b.x;
	if(a.y!=b.y) return a.y<b.y;
	return a.z<b.z;
}
inline bool cmp2(node &a,node &b){	//按二维排序
	if(a.y!=b.y) return a.y<b.y;
	if(a.z!=b.z) return a.z<b.z;
	return a.x<b.x; 
}
int n,m,k;
struct BIT{		// BIT维护三维
	#define lowbit(x) x&(-x)
	#define il inline
	ll s[N];
	il void upd(int x,int v){
		while(x<=k){
			s[x]+=v;x+=lowbit(x);
		}return;
	}
	il ll que(int x){
		ll ans=0;
		while(x){
			ans+=s[x];x-=lowbit(x);
		}return ans;
	}
}T;
void cdq(int l,int r){	//cdq分治
	if(l==r) return;
	int m=l+r>>1;//分治解决左区间内部答案  和 右区间内部答案.
	cdq(l,m),cdq(m+1,r);sort(b+l,b+m+1,cmp2),sort(b+m+1,b+r+1,cmp2);
	//按照二维排好序,便于双指针.
	int i,j;//i指向左区间,j指向右区间.
	for(i=l,j=m+1;j<=r;j++){
		while(b[j].y>=b[i].y&&i<=m){	
		//对于当前j 将所有二维小于等于它的第三维加入BIT
			T.upd(b[i].z,b[i].c);
			i++;
		}
		//更新b[j]的答案.
		b[j].v+=T.que(b[j].z);
	}
	for(int x=l;x<i;x++) T.upd(b[x].z,-b[x].c);	//清空BIT
}
int ans[N];
int main(){
	read(n),read(k);
	for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),read(a[i].z);
	int cnt=0;
	sort(a+1,a+n+1,cmp1);	//一维排序
	for(int i=1;i<=n;++i){	//去重
		cnt++;
		if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y||a[i].z!=a[i+1].z){
			++m;
			b[m]=a[i];
			b[m].c=cnt;
			cnt=0;
		}
	}
	cdq(1,m);
	//题意要求i!=j  所以b[i].v + b[i].c  之后还要减1. 
	//这里b[i].v 是小于它的所有j的个数, b[i].c 是等于它的个数.
	for(int i=1;i<=m;i++) ans[b[i].v+b[i].c-1]+=b[i].c; 
	for(int i=0;i<n;i++) printf("%d\\n",ans[i]);
	return 0;
}

四维偏序

HDU 5126stars

给定 Q Q Q操作, o p = 1 op=1 op=1 插入 ( x , y , z ) (x,y,z) (x,y,z)三维序对, o p = 2 op=2 op=2询问在 x ∈ [ x 1 , x 2 ] , y ∈ [ y 1 , y 2 ] , z ∈ [ z 1 , z 2 ] x\\in [x_1,x_2],y\\in [y_1,y_2],z\\in[z_1,z_2] x[x1,x2],y[y1,y2],z[z1,z2]的三维序对有多少个。

询问容斥下,就可以当成前缀和,然后可以套BIT了。

把时间(也就是询问顺序)当成一维,因为题目就是按顺序给的,所以一维解决了。

x , y x,y x,y 两个维度分别cdq 两次。

z z z 维度 B I T BIT BIT ,因为值域较大, z z z维度先离散化下即可。

时间复杂度: O ( n l o g 3 n ) O(nlog^3n) O(nlog3n)

具体细节看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=5e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	n--;
	for(int i=0;i<n;i++)
		printf("%d ",a[i]模板:CDQ分治

初窥CDQ分治

HDU 3507 Print Article(CDQ分治+分治DP)

bzoj 2683 简单题 cdq分治

bzoj4237: 稻草人 cdq分治 单调栈

cdq分治浅谈