离线算法入门——CDQ分治
离线算法入门——CDQ分治
1 简介
CDQ 分治只能算作一种方法而非一种通用的算法,对于一段操作序列,我们从中间分开,先处理左边,再处理右边,最后加上左边对右边的影响。归并排序实际上就是一个 CDQ 分治。
2 例题
2.1 三维偏序
我们首先按照第一维从大到小排序。这样接下来我们只需要考虑第二第三层。考虑 CDQ 分治,如何统计左边对右边的贡献呢?我们可以把两边都按照第二维排序,然后用双指针统计答案。
需要注意的是,如果两个元素第一维相同,第二维不同,我们需要让左边的第二维严格小于右边。否则这个答案就可能统计不上,因为相同的元素如果划分到一个区域里可能统计不了答案,我们需要提前去重。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 200010
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,k,f[N],tong[N];
struct BIT{
int p[N];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int val){for(int i=x;i<=k;i+=lowbit(i))p[i]+=val;}
inline int ask_sum(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i)) ans+=p[i];return ans;}
};
BIT bit;
struct flower{
int a,b,c,cnt,ans;
inline bool operator == (const flower &b) const{
return (a==b.a)&&(this->b==b.b)&&(c==b.c);
}
};
flower fl[N];
inline bool cmp1(flower a,flower b){
if(a.a!=b.a) return a.a<b.a;
else if(a.b!=b.b) return a.b<b.b;
else return a.c<b.c;
}
inline bool cmp2(flower a,flower b){
if(a.b!=b.b) return a.b<b.b;
else return a.c<b.c;
}
inline void cdq(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
sort(fl+l,fl+mid+1,cmp2);
sort(fl+mid+1,fl+r+1,cmp2);
int i=l,j=mid+1;
for(;j<=r;j++){
while(fl[i].b<=fl[j].b&&i<=mid){
bit.add(fl[i].c,fl[i].cnt);i++;
}
fl[j].ans+=bit.ask_sum(fl[j].c);
}
for(int w=l;w<i;w++) bit.add(fl[w].c,-fl[w].cnt);
}
int main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);read(k);
for(int i=1;i<=n;i++){
read(fl[i].a);read(fl[i].b);read(fl[i].c);
}
sort(fl+1,fl+n+1,cmp1);
int tail=0;fl[++tail]=fl[1];fl[tail].cnt=1;
for(int i=2;i<=n;i++){
if(fl[i]==fl[i-1]){
fl[tail].cnt++;
}
else fl[++tail]=fl[i],fl[tail].cnt=1;
}
cdq(1,tail);
for(int i=1;i<=tail;i++) tong[fl[i].ans+fl[i].cnt-1]+=fl[i].cnt;
for(int i=0;i<=n-1;i++) printf("%d\n",tong[i]);
return 0;
}