#CDQ分治#洛谷 3810 bzoj 3262 陌上花开

本文深入解析CDQ分治算法结合树状数组的应用,通过具体代码实例,详细阐述了如何实时维护和更新数据结构,实现高效的数据查询与处理。特别关注于分治策略下的树状数组恢复过程,为复杂问题提供了一种有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目


分析

CDQ板子,用树状数组实时维护,分治完后要恢复树状数组


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=100101;
int n,m,ans[N],k,a[N],b[N],c[N],rk[N],qk[N],w[N],cnt[N],h[N<<1];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline bool cmp(int x,int y){return a[x]<a[y]||(a[x]==a[y]&&(b[x]<b[y]||(b[x]==b[y]&&c[x]<c[y])));}
inline void update(int x,int y){for (;x<=k;x+=-x&x) h[x]+=y;}
inline signed answ(int x){rr int ans=0; for (;x;x-=-x&x) ans+=h[x]; return ans;}
inline void cdq(int *rk,int n){
	if (n==1) return;
	rr int mid=n>>1,i,j,k;
	cdq(rk,mid),cdq(rk+mid,n-mid);
	memcpy(qk,rk,n<<2);
	for (k=i=0,j=mid;i<mid&&j<n;++k){
		rr int x=qk[i],y=qk[j];
		if (b[x]<=b[y]) update(c[rk[k]=x],w[x]),++i;
		    else cnt[y]+=answ(c[rk[k]=y]),++j;
	}
	for (;j<n;++j) cnt[qk[j]]+=answ(c[qk[j]]);
	memcpy(rk+k,qk+i,(mid-i)<<2);
	for (--i;~i;--i) update(c[qk[i]],-w[qk[i]]);
}
signed main(){
	m=iut(); k=iut();
	for (rr int i=0;i<m;++i) rk[i]=i,a[i]=iut(),b[i]=iut(),c[i]=iut();
	sort(rk,rk+m,cmp);
	for (rr int i=1;i<m;++i){
		rr int x=rk[i],y=rk[n]; ++w[y];
		if ((a[x]^a[y])||(b[x]^b[y])||(c[x]^c[y])) rk[++n]=x;
	}
	++w[rk[n]],++n; cdq(rk,n);
	for (rr int i=0;i<n;++i) ans[cnt[rk[i]]+w[rk[i]]-1]+=w[rk[i]];
	for (rr int i=0;i<m;++i) print(ans[i]),putchar(10);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值