cdq分治一般是解决具有一下两种性质的问题(只有修改和查询操作):
1.只能用离线做法。
2.每个修改操作对询问的影响是独立的,即与之前的修改操作无关。
cdq分治与一般的分治不同,一般的分治分出来的子区间是独立的,个个击破即可,
而cdq分治分出来的两个子区间是相互联系的。(以下的分治都是指cdq分治)
由于在该问题中,每个询问只与在此之前的修改操作有关。
对于区间l,mid,记为区间1,区间mid+1,r,记为区间2,
过程:
1.递归处理区间(1),
2.递归处理区间(2),
3.统计区间1中的修改操作对区间2中的询问操作的影响。
4.算法结束。
CDQ分治模板题:https://blog.csdn.net/baodream/article/details/82666950
CDQ分治可求三维偏序,代码模板:
//CDQ分治,可用于求三维偏序,复杂度O(nlogn)
const int N = 2e5+5;
struct node{
int x,y,z;
int id;
}a[N],tmp[N];
int ans[N],cnt[N]; //ans[i]代表比第i个点小的点有多少个
int n,k; //n代表点的个数,k代表点的范围
bool cmp(node a,node b){
if(a.x==b.x&&a.y==b.y)
return a.z<b.z;
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
int tree[N]; //tree数组按二进制存,根据n的末尾0的个数存取,树状数组
int lowbit(int x)
{
return x&(-x);
}
int Query(int x) //返回1到x的前缀和
{
int res=0;
while(x)
{
res+=tree[x];
x-=lowbit(x);
}
return res;
}
void Add(int x,int v) //实现a[x]+v;
{
while(x<=k) //注意这里是小于等于k,不是n,k是数据范围
{
tree[x]+=v;
x+=lowbit(x);
}
}
void clearr(int x){
while(x<=k){
if(tree[x]==0)
break;
tree[x]=0;
x+=lowbit(x);
}
}
void cdq(int l,int r){
//cout<<"l "<<l<<" r "<<r<<endl;
if(l>=r)
return ;
int mid = l+r>>1;
cdq(l,mid);
cdq(mid+1,r);
int p=l,q=mid+1,k=l;
while(p<=mid&&q<=r){
if(a[p].y<=a[q].y){
Add(a[p].z,1);
tmp[k++] = a[p++];
}
else{
ans[a[q].id]+=Query(a[q].z);
tmp[k++] = a[q++];
}
}
while(p<=mid){
Add(a[p].z,1);
tmp[k++] = a[p++];
}
while(q<=r){
ans[a[q].id]+=Query(a[q].z);
tmp[k++] = a[q++];
}
for(int i=l;i<=r;i++){
clearr(a[i].z);
a[i] = tmp[i];
}
/*
cout<<"*** l "<<l<<" ** r "<<r<<endl;
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
cout<<endl;
*/
}
bool compare(node a,node b){
if(a.x==b.x&&a.y==b.y&&a.z==b.z)
return true;
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
std::ios::sync_with_stdio(false);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].id = i;
}
sort(a+1,a+1+n,cmp); //一维用sort保证,二维归并的时候保证,三维树状数组保证
node temp = {-1,-1,-1,-1};
int res = 0;
for(int i=n;i>=1;i--){ //这里处理一下后面相同的个数,因为分治的时候处理不了后面的
if(compare(temp,a[i])){
ans[a[i].id]+=res;
res++;
}
else{
temp = a[i];
res=1;
}
}
cdq(1,n); //cdq分治求答案
/*for(int i=1;i<=n;i++)
printf("ans[%d]=%d\n",i,ans[i]);*/
for(int i=1;i<=n;i++)
cnt[ans[i]]++;
for(int i=0;i<n;i++)
printf("%d\n",cnt[i]); //cnt[i]是每一级的点的个数
return 0;
}