【BZOJ 3262】-陌上花开(CDQ分治+树状数组)

传送门

CDQ分治练习题

首先以第一维为关键字排序

然后这样就只剩两维了

就像常规的CDQCDQCDQ分治一样

处理二维偏序关系就可以了

将满足第二维关系的的三维放在一个树状数组维护查询就可以了

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
} 
const int N=400005;
struct flw{
	int a,b,c,cnt,ans;
}a[N],p[N];
inline bool cmp(const flw &a,const flw &b){
	if(a.a==b.a&&a.b==b.b)return a.c<b.c;
	if(a.a==b.a)return a.b<b.b;
	return a.a<b.a;
}
inline bool comp(const flw &a,const flw &b){
	if(a.b==b.b)return a.c<b.c;
	return a.b<b.b;
}
int tr[N],n,m,tot,cnt,ans[N];
inline int lowbit(int x){return (x&(-x));}
inline void update(int pos,int k){for(;pos<=m;pos+=lowbit(pos))tr[pos]+=k;}
inline int query(int pos,int res=0){for(;pos;pos-=lowbit(pos))res+=tr[pos];return res;}
#define mid ((l+r)>>1)
inline void cdq(int l,int r){
	if(l==r)return;
	cdq(l,mid),cdq(mid+1,r);
	sort(a+l,a+mid+1,comp);
	sort(a+mid+1,a+r+1,comp);
	int i=l;
	for(int j=mid+1;j<=r;j++){
		while(i<=mid&&a[i].b<=a[j].b){
			update(a[i].c,a[i].cnt),i++;
		}
		a[j].ans+=query(a[j].c);
	}
	for(int j=l;j<i;j++)update(a[j].c,-a[j].cnt);
}
#undef mid
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		p[i].a=read(),p[i].b=read(),p[i].c=read();
	}
	sort(p+1,p+n+1,cmp);
	for(int i=1;i<=n;i++){
		cnt++;
		if(p[i].a!=p[i+1].a||p[i].b!=p[i+1].b||p[i].c!=p[i+1].c){
			a[++tot]=p[i],a[tot].cnt=cnt,cnt=0;
		}
	}
	cdq(1,tot);
	for(int i=1;i<=n;i++){
		ans[a[i].ans+a[i].cnt-1]+=a[i].cnt;
	}
	for(int i=0;i<n;i++){
		cout<<ans[i]<<"\n";
	}
}

转载于:https://www.cnblogs.com/stargazer-cyk/p/10366359.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值