Bzoj【3262】陌上花开

传送门biu~

CDQ分治第一题。。。上次集训还认为是大神的东西,没想到现在就学了。。。

CDQ分治可以看做降维打击,大体思路是先把一段区间分为两部分,只考虑左半部分对右半部分的影响,常数小还好写,可以顶替复杂高级数据结构,只是必须离线

AC Code

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct flower
{
	int x,y,z;
	int cnt,ans;
}a[1000005];
int c[3000005],n,k,tot,num[1000005];
bool cmp(flower a,flower b)
{
	if(a.x<b.x) return 1;
	if(a.x>b.x) return 0;
	if(a.y<b.y) return 1;
	if(a.y>b.y) return 0;
	if(a.z<b.z) return 1;
	return 0;
}
bool cmp2(flower a,flower b)
{
	if(a.y<b.y) return 1;
	if(a.y>b.y) return 0;
	if(a.z<b.z) return 1;
	if(a.z>b.z) return 0;
	if(a.x<b.x) return 1;
	return 0;
}
inline int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	while(x<=k)
	{
		c[x]+=y;
		x+=lowbit(x);
	}
}
int ask(int x)
{
	int ans=0;
	while(x)
	{
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
void CDQ(int l,int r)
{
	if(l==r)
	{
	a[l].ans+=a[l].cnt-1;
	return ;	
	}
	int mid=(l+r)>>1;
	CDQ(l,mid);
	CDQ(mid+1,r);
	sort(a+l,a+1+mid,cmp2);
	sort(a+mid+1,a+r+1,cmp2);
	int j=l;
	for(int i=mid+1;i<=r;i++)
	{
		while(j<=mid&&a[j].y<=a[i].y)add(a[j].z,a[j].cnt),j++;
		a[i].ans+=ask(a[i].z);
	}
	for(int i=l;i<j;i++)
	add(a[i].z,-a[i].cnt);
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].ans=1;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++)
	if(i!=1&&a[i].x==a[i-1].x&&a[i].y==a[i-1].y&&a[i].z==a[i-1].z)a[tot].cnt++;
	else a[++tot]=a[i],a[tot].cnt=1;
	CDQ(1,tot);
	sort(a+1,a+tot+1,cmp);
	for(int i=1;i<=tot;i++)num[a[i].ans]+=a[i].cnt;
	for(int i=1;i<=n;i++)printf("%d\n",num[i]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值