其他分享
首页 > 其他分享> > 【BZOJ 3262】陌上花开

【BZOJ 3262】陌上花开

作者:互联网

【题目】

传送门

题目描述:

nnn 朵花,每朵花有三个属性:花形 (s)(s)(s)、颜色 (c)(c)(c)、气味 (m)(m)(m),用三个整数表示。

现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。

定义一朵花 A 比另一朵花 B 要美丽,当且仅 sasb,cacb,mambs_a≥s_b,c_a≥c_b,m_a≥m_bsa​≥sb​,ca​≥cb​,ma​≥mb​。

显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

输入格式:

第一行为 n,k(1n100,000,1k200,000)n,k (1 \le n \le 100,000, 1 \le k \le 200,000 )n,k(1≤n≤100,000,1≤k≤200,000),分别表示花的数量和最大属性值。

以下 nnn 行,每行三个整数 si,ci,mi(1si,ci,mik)s_i, c_i, m_i (1 \le s_i, c_i, m_i \le k)si​,ci​,mi​(1≤si​,ci​,mi​≤k),表示第 iii 朵花的属性。

输出格式:

包含 nnn 行,分别表示评级为 0,1,,n10,1,\dots,n-10,1,…,n−1 的每级花的数量。

样例数据:

输入
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

输出
3
1
3
0
1
0
1
0
0
1


【分析】

这就是一道三位偏序的模板题啦,用 CDQ\mathrm{CDQ}CDQ 分治就可以轻松解决。

先把第一位排序,这样就消掉了第一维的影响,就把问题变成了二维偏序。

然后开始分治,分治的时候有点类似求逆序对的过程。

我们把第二维排序,然后用树状数组维护第三维就可以了。

注意要去重。

如果没看懂的话就找其他博客吧。


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define K 200005
#define lowbit(x) ((x)&(-x))
using namespace std;
int n,k,tot;
int bit[K],ans[N];
struct flower{int a,b,c,cnt,num;}p[N];
bool comp(const flower &p,const flower &q)
{
	if(p.a!=q.a)  return p.a<q.a;
	if(p.b!=q.b)  return p.b<q.b;
	return p.c<q.c;
}
bool Comp(const flower &p,const flower &q)
{
	if(p.b!=q.b)  return p.b<q.b;
	return p.c<q.c;
}
void add(int i,int x)  {for(;i<=k;i+=lowbit(i))bit[i]+=x;}
int query(int i,int ans=0)  {for(;i;i-=lowbit(i))ans+=bit[i];return ans;}
void solve(int l,int r)
{
	if(l==r)  return;
	int mid=(l+r)>>1;
	solve(l,mid),solve(mid+1,r);
	sort(p+l,p+mid+1,Comp);
	sort(p+mid+1,p+r+1,Comp);
	int i=l,j;
	for(j=mid+1;j<=r;++j)
	{
		while(i<=mid&&p[i].b<=p[j].b)
		  add(p[i].c,p[i].cnt),i++;
		p[j].num+=query(p[j].c);
	}
	for(j=l;j<i;++j)  add(p[j].c,-p[j].cnt);
}
int main()
{
	int i,t=0;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;++i)
	  scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
	sort(p+1,p+n+1,comp);
	for(i=1;i<=n;++i)
	{
		t++;
		if(p[i].a!=p[i+1].a||p[i].b!=p[i+1].b||p[i].c!=p[i+1].c)
		  p[++tot]=p[i],p[tot].cnt=t,t=0;
	}
	solve(1,tot);
	for(i=1;i<=tot;++i)  ans[p[i].num+p[i].cnt-1]+=p[i].cnt;
	for(i=0;i<n;++i)  printf("%d\n",ans[i]);
	return 0;
}

标签:ci,le,int,mi,陌上,mid,000,3262,BZOJ
来源: https://blog.csdn.net/forever_dreams/article/details/88535484