CDQ分治

放一个cdq分治板子。
是洛谷陌上花开代码搬过来的。感觉要点在于去重(完全相同的点),没了。
第一维直接排序
第二维cdq分治,因为合并时前一半的a必然小于后一半的,所以可以重新按b排序算前面的数对于后面的数贡献。
第三维树状数组需要每次清空算c的贡献
这样就是一个\(O(logn^2)\)

#include<bits/stdc++.h>
using namespace std;
#define ls(x) (x<<1)
#define rs(x) ((x<<1)+1)
#define lowbit(x) (x&(-x)) 
const int maxn=2e5+10;
struct Node{
	int a,b,c,id;
	bool vis=0;
}node[maxn];
int f[maxn],t[maxn*2],num[maxn],bj[maxn];

bool cmp(const Node &x,const Node &y){
	if(x.a!=y.a)return x.a<y.a;
	if(x.b!=y.b)return x.b<y.b;
	return x.c<y.c;
}
bool cmp2(const Node &x,const Node &y){
	if(x.b!=y.b)return x.b<y.b;
	if(x.c!=y.c)return x.c<y.c;
	return x.a<y.a;
}
void modify(int x,int k){
	while(x<maxn){
		t[x]+=k;
		x+=lowbit(x);
	}
	return;
}
int que(int x){
	int res=0;
	while(x>0){
		res+=t[x];
		x-=lowbit(x);
	}
	return res;
}
void merge(int l,int mid,int r){
	sort(node+l,node+r+1,cmp2);
	for(int i=l;i<=r;i++){
		//cout<<node[i].a<<endl;;
		if(node[i].a<=mid)modify(node[i].c,1);
		else f[node[i].id]+=que(node[i].c);
	}
	for(int i=l;i<=r;i++)
		if(node[i].a<=mid)modify(node[i].c,-1);
	
}
void cdq(int l,int r){
	if(l==r)return;
	int mid=(l+r)>>1;
	cdq(l,mid);
	cdq(mid+1,r);
	merge(l,mid,r);
}
signed main(){
	int n,k;cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>node[i].a>>node[i].b>>node[i].c;
		node[i].id=i;
	}	
	sort(node+1,node+n+1,cmp);
	for(int i=1;i<=n;){
		int j=i+1;
		while(j<=n&&node[j].a==node[i].a&&node[j].b==node[i].b&&node[j].c==node[i].c)
			j++;
		while(i<j)
			bj[node[i].id]=node[j-1].id,i++;
	}
	for(int i=1;i<=n;i++)node[i].a=i;
	cdq(1,n);
	for(int i=n;i>=1;i--){
		num[f[bj[node[i].id]]]++;
	}
	for(int i=0;i<n;i++)cout<<num[i]<<"\n";
}
posted @ 2024-08-29 00:55  lyrrr  阅读(36)  评论(0)    收藏  举报