ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3810 【模板】三维偏序(陌上花开)(CDQ分治)

2021-11-02 12:33:51  阅读:267  来源: 互联网

标签:偏序 int ll 分治 mid P3810 CDQ include e2


jisoo

典型的CDQ分治

一维的时候比较就行了

二维的时候加一个数据结构,就像逆序对一样

三维的时候则需要,使用CDQ分治来解决了

首先把全局按照第一维从小到大排序,相同的按照第二维,还相同的按照第三维

然后开始从中间分开,分治。

显然这个过程位于 \(mid\) 两边内部的都会在自己的过程中被解决,新的贡献来自于跨过mid的比较。

这一部分怎么处理呢?首先两边都按照第二维排序。按照类似于归并的方式每一部分进行一个指针,把前面的和后面的部分比较第二维,并且把第二维小于后半部分的前半部分的元素扔到一个树状数组里(处理第三位)

这样我们就找到了第一维,第二维都小于后面元素的元素,再按照类似于求逆序对的思想,用树状数组查询其中第三维也比他小的元素的数量

搞定

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
const int maxn=200005;
struct e{
	int x;
	int y;
	int c;
	int num;
	int ans;
}el[maxn],e2[maxn];
bool cmp1(e x,e y){
	if(x.x==y.x) return x.y==y.y?x.c<y.c:x.y<y.y;
	else return x.x<y.x;
}
bool cmp2(e x,e y){
	return x.y==y.y?x.c<y.c:x.y<y.y;
}
int cnt;
int n,k;
int tr[maxn];
int lowbit(int x){
	return x&-x;
}
void add(int x,int kk){
	for(int i=x;i<=k;i+=lowbit(i)){
		tr[i]+=kk;
	}
}
int qu(int x){
	int ans=0;
	while(x){
		ans+=tr[x];
		x-=lowbit(x);
	}
	return ans;
}
int x,y,z;
long long ans[maxn];
void cdq(int l,int r){
	if(l==r) return ;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(e2+l,e2+mid+1,cmp2);
	sort(e2+mid+1,e2+r+1,cmp2);
	int ll=l;
	for(int rr=mid+1;rr<=r;++rr){
		while(e2[rr].y>=e2[ll].y&&ll<=mid){
			add(e2[ll].c,e2[ll].num);
			ll++;
		}
		e2[rr].ans+=qu(e2[rr].c);
	}
	for(int i=l;i<ll;++i){
		add(e2[i].c,-e2[i].num);
	}
}
int main(){
	read(n);read(k);
	for(int i=1;i<=n;++i){
		read(el[i].x);read(el[i].y);read(el[i].c);
	}
	sort(el+1,el+n+1,cmp1);
	for(int i=1;i<=n;++i){
		if(el[i].x!=el[i-1].x||el[i].y!=el[i-1].y||el[i].c!=el[i-1].c){
			cnt++;
			e2[cnt].x=el[i].x;
			e2[cnt].y=el[i].y;
			e2[cnt].c=el[i].c;
			e2[cnt].num=1;
		}else{
			e2[cnt].num++;
		}
	}
	cdq(1,cnt);
	for(int i=1;i<=cnt;++i){
		ans[e2[i].ans+e2[i].num-1]+=e2[i].num;
	}
	for(int i=0;i<n;++i){
		cout<<ans[i]<<endl;
	}
	return 0;
}

标签:偏序,int,ll,分治,mid,P3810,CDQ,include,e2
来源: https://www.cnblogs.com/For-Miku/p/15498314.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有