【cdq分治】【模板】

Problem

三维偏序的模板题。

Solution:

经典做法是,先排序控制一维,再用cdq分治控制一维,最后用数据结构(通常是树状数组)维护一维。

cdq分治还可以嵌套,每嵌套一次,复杂度乘一个log,可以拓展到n维偏序(但超过3维,效率就很低了,通常会使用kd-tree),因此,这题也可以用两个cdq分治嵌套解决(但我不会)

复杂度O(n log^2 n),cdq分治和树状数组各提供一个log

需要注意的问题:

在cdq分治的外层排序中,必须要满足在cdq内部划分时,右半区间不能对左半区间造成影响,因此,当两个元素完全相同时,需要把他们合成一个元素,最后再累计相同元素的贡献,而且要按照三关键字排序

Code

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {ch=getchar();w=-1;}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) {putchar('-');x=~(x-1);}
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=1e5+100;
int n,k;
struct node{
	int a,b,c,s,ans;
	bool operator<(const node&x)const{
	     if(a!=x.a) return a<x.a;
	     if(b==x.b) return c<x.c;
	     return b<x.b;
	}
	bool operator==(const node&x)const{
	     return a==x.a&&b==x.b&&c==x.c;
	}
}a[N];
int t[N<<1];
int cnt;
bool cmp(node x,node y)
{
	return x.b<y.b;
}
void add(int x,int c)
{
	for(int i=x;i<=k;i+=i&-i)
	t[i]+=c;
}
int ask(int x)
{
	int res=0;
	for(int i=x;i;i-=i&-i)
	res+=t[i];
	return res;
}
void cdq(int l,int r)
{
	if(l==r) return;
	int mid=l+r>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
	int pos=l;
	for(int i=mid+1;i<=r;++i)
	{
		while(pos<=mid&&a[pos].b<=a[i].b) {
			add(a[pos].c,a[pos].s);pos++;
		}
		a[i].ans+=ask(a[i].c);
	}
	for(int i=l;i<pos;++i) add(a[i].c,-a[i].s);
}
int d[N];
int main()
{
    n=read();k=read();
    for(int i=1;i<=n;++i){
    	a[i].a=read();
    	a[i].b=read();
    	a[i].c=read();
    	a[i].s=1;
	}
	sort(a+1,a+n+1);
//	int cnt=0;
	for(int i=1;i<=n;++i)
	if(a[i]==a[cnt]) a[cnt].s++;
	else a[++cnt]=a[i];
	cdq(1,cnt);
	for(int i=1;i<=cnt;++i)
	d[a[i].ans+a[i].s-1]+=a[i].s;
	for(int i=0;i<n;++i){
		write(d[i]);puts("");
	}
	return 0;
}

cdq分治的递归函数跟归并排序十分类似,实际上,我们可以把cdq中的sort改为归并排序,从而减少常数。

常数优化版本

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {ch=getchar();w=-1;}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) {putchar('-');x=~(x-1);}
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=1e5+100;
int n,k;
struct node{
	int a,b,c,s,ans;
	bool operator<(const node&x)const{
	     if(a!=x.a) return a<x.a;
	     if(b==x.b) return c<x.c;
	     return b<x.b;
	}
	bool operator==(const node&x)const{
	     return a==x.a&&b==x.b&&c==x.c;
	}
}a[N],tmp[N];
int t[N<<1];
int cnt;
bool cmp(node x,node y)
{
	return x.b<y.b;
}
void add(int x,int c)
{
	for(int i=x;i<=k;i+=i&-i)
	t[i]+=c;
}
int ask(int x)
{
	int res=0;
	for(int i=x;i;i-=i&-i)
	res+=t[i];
	return res;
}
void cdq(int l,int r)
{
	if(l==r) return;
	int mid=l+r>>1;
	cdq(l,mid);cdq(mid+1,r);
//	sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
	int pos=l;
	for(int i=mid+1;i<=r;++i)
	{
		while(pos<=mid&&a[pos].b<=a[i].b) {
			add(a[pos].c,a[pos].s);pos++;
		}
		a[i].ans+=ask(a[i].c);
	}
	for(int i=l;i<pos;++i) add(a[i].c,-a[i].s);
	pos=l-1;
	int p=l,q=mid+1;
	while(p<=mid||q<=r)
	{
		if(p>mid)
		tmp[++pos]=a[q++];
		else if(q>r) tmp[++pos]=a[p++];
		else tmp[++pos]=a[a[p].b<a[q].b?p++:q++];
	}
	for(int i=l;i<=r;++i) a[i]=tmp[i];
}
int d[N];
int main()
{
    n=read();k=read();
    for(int i=1;i<=n;++i){
    	a[i].a=read();
    	a[i].b=read();
    	a[i].c=read();
    	a[i].s=1;
	}
	sort(a+1,a+n+1);
//	int cnt=0;
	for(int i=1;i<=n;++i)
	if(a[i]==a[cnt]) a[cnt].s++;
	else a[++cnt]=a[i];
	cdq(1,cnt);
	for(int i=1;i<=cnt;++i)
	d[a[i].ans+a[i].s-1]+=a[i].s;
	for(int i=0;i<n;++i){
		write(d[i]);puts("");
	}
	return 0;
}
posted @ 2022-02-20 15:39  glq_C  阅读(107)  评论(0)    收藏  举报