[BZOJ3262]:陌上花开(CDQ分治)
题目传送门
题目描述
有$n$朵花,每朵花有三个属性:花形$(s)$、颜色$(c)$、气味$(m)$,用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花$A$比另一朵花$B$要美丽,当且仅$S_a\geqslant S_b,C_a\geqslant C_b,M_a\geqslant M_b$。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
输入格式
第一行为$N,K$,分别表示花的数量和最大属性值。
以下$N$行,每行三个整数$s_i,c_i,m_i$,表示第$i$朵花的属性。
输出格式
包含$N$行,分别表示评级为$0...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
数据范围与提示
$1\leqslant N\leqslant 100,000$。
$1\leqslant K\leqslant 200,000$。
$1\leqslant s_i,c_i,m_i\leqslant K$。
题解
这道题好像可以用$bitset$,$CDQ$分治,$K-Dtree$解决。
$bitset$好像跑不过,我也不清楚……
最尴尬的是$K-Dtree$我不会……
那么我就来讲讲$CDQ$分治。
假设我们不考虑$m_i$,那么我们就变成了二元组排序,可以先将$s_i$排序,然后问题就转化成了:在一个数列里,找在$i$之前有几个数小于$c_i$。
很显然要使用树状数组维护即可在$\Theta (n\log n)$时间内求出答案。
那么现在又加了一维,怎么办呢?
首先,将这个三元组排序并去重,那么权值$a$已经随下标有序。
然后我们就需要引入$CDQ$分治,假设当前处理的区间为$[L,R]$其中点为$M$,那么我们在处理当前区间的时候已经保证了$[L,M]$和$[M+1,R]$的有序,因为$[L,M]$中的$s_i$一定小于等于$[M+1,R]$中的$s_i$,所以我们只需要维护一个单调指针,按照$[L,M]$中的$c_i$的大小从小到大将其放入树状数组,并在其中查询前缀和即可。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec
{
int s;
int c;
int m;
int x;
int id;
}e[2000001];
int n,k;
int tr[8000001];
int ans[2000001],q[2000001],b[2000001];
bool cmp1(rec a,rec 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);}
bool cmp2(rec a,rec b){return a.c<b.c||(a.c==b.c&&a.m<b.m)||(a.c==b.c&&a.m==b.m&&a.x<b.x);}
int lowbit(int x){return x&-x;}
void add(int x,int y)
{
while(x<=k)
{
tr[x]+=y;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x)
{
res+=tr[x];
x-=lowbit(x);
}
return res;
}
void cdq(int l,int r)//cdq分治
{
if(l==r)return;
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
sort(e+l,e+r+1,cmp2);
for(int i=l;i<=r;i++)
if(e[i].x<=mid)add(e[i].m,1);
else q[e[i].id]+=query(e[i].m);
for(int i=l;i<=r;i++)
if(e[i].x<=mid)add(e[i].m,-1);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&e[i].s,&e[i].c,&e[i].m);
e[i].id=i;
}
sort(e+1,e+n+1,cmp1);
for(int i=1;i<=n;)//手动去重
{
int flag=i+1;
while(flag<=n&&e[i].s==e[flag].s&&e[i].c==e[flag].c&&e[i].m==e[flag].m)flag++;
flag--;
while(i<=flag)
{
b[e[i].id]=e[flag].id;
i++;
}
}
for(int i=1;i<=n;i++)e[i].x=i;
cdq(1,n);
for(int i=1;i<=n;i++)
ans[q[b[e[i].id]]]++;
for(int i=0;i<n;i++)
printf("%d\n",ans[i]);
return 0;
}
rp++