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分治