【BZOJ 3262】陌上花开
作者:互联网
【题目】
题目描述:
有 n 朵花,每朵花有三个属性:花形 (s)、颜色 (c)、气味 (m),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花 A 比另一朵花 B 要美丽,当且仅 sa≥sb,ca≥cb,ma≥mb。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
输入格式:
第一行为 n,k(1≤n≤100,000,1≤k≤200,000),分别表示花的数量和最大属性值。
以下 n 行,每行三个整数 si,ci,mi(1≤si,ci,mi≤k),表示第 i 朵花的属性。
输出格式:
包含 n 行,分别表示评级为 0,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 分治就可以轻松解决。
先把第一位排序,这样就消掉了第一维的影响,就把问题变成了二维偏序。
然后开始分治,分治的时候有点类似求逆序对的过程。
我们把第二维排序,然后用树状数组维护第三维就可以了。
注意要去重。
如果没看懂的话就找其他博客吧。
【代码】
#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