CDQ70分求调,代码有详细解释
查看原帖
CDQ70分求调,代码有详细解释
287411
_脑波_楼主2023/3/19 15:13
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;


inline int read(){
	char ch=getchar();
	int fh=0;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')fh=(fh<<3)+(fh<<1)+(ch^48),ch=getchar();
	return fh;
}


struct node{
	int a,b,c,cnt,ans;
}e[N],f[N];
int n,k,answ[N],cf,m;


class tree_bl{
	public:
		inline void set(int many,int fjlvm){how_many=many;tree=new int[fjlvm];}
		//set数的个数以及树状数组大小
		inline void add_wh(int node,int data){while(node<=how_many){tree[node]+=data;node+=lowbit(node);}}
		//while的修改
		inline void add_dg(int node,int data){if(node>how_many)return ;tree[node]+=data;add_dg(node+lowbit(node),data);}
		//递归的修改
		inline void add_fo(int node,int data){for(;node<=how_many;node+=lowbit(node))tree[node]+=data;}
		//for的修改
		inline int ask(int what){int fh=0;while(what){fh+=tree[what];what=what-lowbit(what);}return fh;}
		//查询
		#define add add_wh
		inline void delete_tree(void){delete[] tree;}
		//删除树状数组
		friend void debug_tree(tree_bl &shuzu);
		//输出树状数组内数字
	private:
		int how_many;
		int *tree;
		inline int lowbit(int X){return X&(-X);}
};
void debug_tree(tree_bl &shuzu){
	putchar('\n');
	for(int i=0;i<=shuzu.how_many;i=-~i)std::cout<<shuzu.tree[i]<<'\n';
	putchar('\n');
}
tree_bl tr;//建立树状数组


inline bool cmp1(node ldr,node zc){
	return ldr.a==zc.a?(ldr.b==zc.b?ldr.c<zc.c:ldr.b<zc.b):ldr.a<zc.a;
}
inline bool cmp2(node ldr,node zc){
	return ldr.b==zc.b?ldr.c<zc.c:ldr.b<zc.b;
}


void cdq(int l,int r){
	if(l==r)return ;
	int mid=(l+r)>>1;
	cdq(l,mid),cdq(mid+1,r);//向下二分
	sort(f+l,f+mid+1,cmp2),sort(f+mid+1,f+r+1,cmp2);
	//排序合并下面两个区间,计算相互影响
	int j=l;//j从l~mid,i从mid+1~r
	for(int i=mid+1;i<=r;i=-~i){
		while(f[i].b>=f[j].b&&j<=mid){
			tr.add(f[j].c,f[j].cnt);
			++j;
		}
		f[i].ans+=tr.ask(f[i].c);//判断是否符合
	}//类似归并排序
	for(int i=l;i<j;i=-~i)tr.add(f[i].c,-f[i].cnt);//删除结点
}


int main(){
	n=read(),k=read();
	for(int i=1;i<=n;i=-~i)e[i].a=read(),e[i].b=read(),e[i].c=read();
	sort(e+1,e+1+n,cmp1);
	//将三维偏序问题转换为二维,此时aj<=ai的限制条件已然失效
	//j<mid i>mid 此时j<i,aj必然小于ai
	for(int i=1;i<=n;i=-~i){
		++cf;
		if(e[i].a!=e[i+1].a||e[i].b!=e[i+1].b||e[i].c!=e[i+1].c){
			++m;
			f[m].a=e[i].a;
			f[m].b=e[i].b;
			f[m].c=e[i].c;
			f[m].cnt=cf;
			cf=0;
		}
	}
	//去重转换到f数组进行cdq
	//因为此题要考虑等于的情况,而原版CDQ只考虑严格大于/小于情况
	//可以手模一下就知道不去重不行
	tr.set(m,N);
	cdq(1,m);
	for(int i=1;i<=m;i=-~i)answ[f[i].ans+f[i].cnt-1]+=f[i].cnt;
	for(int i=1;i<=n;i=-~i)printf("%d\n",answ[i-1]);
}

思路是题解的第一篇,我们教练让我们自己学习给大家分享,所以代码有详细解释

2023/3/19 15:13
加载中...