[BZOJ 3262]陌上花开

Description
有n朵花,每朵花有三个属性:花形(s)、颜色©、气味(m),用三个整数表示。现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅 S a > = S b S_a>=S_b Sa>=Sb, C a > = C b C_a>=C_b Ca>=Cb, M a > = M b M_a>=M_b Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

Input
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性。

Output
包含N行,分别表示评级为0…N-1的每级花的数量。

Sample Input

10 3
3 3 3
2 3 3 
2 3 1 
3 1 1 
3 1 2 
1 3 1 
1 1 2 
1 2 2 
1 3 2 
1 2 1

Sample Output

3
1
3
0
1
0
1
0
0
1

思路
首先按照题目定义,两朵属性完全相同的花都比对方要美丽,所以读入所有花的数据之后有必要排序去重,记录一下每种(三元组)属性的花的数量。
然后没什么想法。。。。。
开始面向题解编程
看了下网上的题解,说是cdq分治套树状数组。
考虑将待处理的序列先按S排序,再将序列一分两半,我们分别计算完了这两半的答案,那么剩下的需要计算的答案就是左边对右边的贡献(考虑先前是按S排序故一定满足左边的S小于或等于右边的S)
这时我们分别对左边一半和右边一半按C排序,再分别建立两个指针用于遍历左边一半和右边一半。
现在左边一半和右边一半都满足按C升序排列并且左边的S均小于等于右边的S。
我们考虑建立一个树状数组用来计数。sum(n)用于树状数组求和。

  • 左边当前位置的C大于右边当前位置的C:对于右边当前位置,答案加上sum(右边当前位置对应的M值),右边指针+1
  • 左边当前位置的C小于等于右边当前位置的C:对于左边当前位置,在树状数组中插入左边当前位置对应的M值,左边指针+1
    当遍历完右边序列后,清空树状数组。

AC代码

#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct data{
	int s,c,m,num,ans;
}data;
int cmp(data a,data b)
{
	return(a.s<b.s)||(a.s==b.s&&a.c<b.c)||(a.s==b.s&&a.c==b.c&&a.m<b.m);
}
data d[100005];
int su[200005],ans[200005],n,k;
int N=0;
int lowbit(int x)
{
	return (x)&(-x);
}
void inse(int now,int v)
{
	while(now<=k)
	{
		su[now]+=v;
		now+=lowbit(now);
	}
	return;
}
int sum(int x)
{
	int ans=0;
	while(x)
	{
		ans+=su[x];x-=lowbit(x);
	}
	return ans;
}
int cmp2(data a,data b)
{
	return a.c<b.c;
}
void cdq(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)/2;
	cdq(l,mid);cdq(mid+1,r);
	sort(d+l,d+mid+1,cmp2);
	sort(d+mid+1,d+r+1,cmp2);
	int h1=l,h2=mid;
	do
	{
		h2++;
		while(h1<=mid&&d[h1].c<=d[h2].c)
		{
			inse(d[h1].m,d[h1].num+1);h1++;
		}
		d[h2].ans+=sum(d[h2].m);
	}while(h2<r);
	for(int i=l;i<h1;i++)inse(d[i].m,-(d[i].num+1));
	return;
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&d[i].s,&d[i].c,&d[i].m);
	}
	sort(d+1,d+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		if(d[i].c==d[N].c&&d[i].s==d[N].s&&d[i].m==d[N].m)
		{
			d[N].num++;
		}else
		{
			N++;d[N]=d[i];
		}
	}//去重,并计数
	cdq(1,N);
	for(int i=1;i<=N;i++)
	ans[d[i].num+d[i].ans]+=d[i].num+1;
	for(int i=0;i<n;i++)printf("%d\n",ans[i]);
	return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值