Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花A比另一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,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
HINT
Source
思路:三维偏序问题考虑cdq分治,cdq分治和普通的分治不同在于多维护了一个类似归并排序的过程。进行cdq分治之前要保证区间其中一边的操作不能影响另一边的,那么操作就要按照某些特征排列了,比如时间顺序。在本题中排序就要对x、y、z的优先级排序,排完序就能保证右边的不对左边的有贡献了(x、y、z全部一样的先不讨论)。那么左边的哪些对右边的哪些有贡献呢?总不能暴力二重循环扫一遍吧,此时对y的归并排序就发挥作用了,具体看代码。最后xyz相同的肯定排在一块,取他们中的最大值就行。
# include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+30;
int n, k, s[maxn], ans[maxn], tot[maxn];
struct node{
int x, y, z, id;
}a[maxn], tmp[maxn];
bool cmp(node i, node j){
if(i.x != j.x) return i.x <j.x;
else{
if(i.y != j.y) return i.y < j.y;
else return i.z < j.z;
}
}
void update(int pos){
for(int i=pos; i<=k; i+=i&-i) ++s[i];
}
int cal(int pos){
int res = 0;
for(;pos>0;pos-=pos&-pos) res += s[pos];
return res;
}
void clr(int pos){
for(; pos<=k; pos+=pos&-pos){
if(s[pos]) s[pos] = 0;
else break;
}
}
void cdq(int l, int r){
if(l == r) return;
int mid = l+r>>1, cnt=0;
cdq(l, mid);
cdq(mid+1, r);
int L=l, R=mid+1;
while(L<=mid && R<=r){
if(a[L].y <= a[R].y){
update(a[L].z);
tmp[cnt++] = a[L++];
}
else{
ans[a[R].id] += cal(a[R].z);
tmp[cnt++] = a[R++];
}
}
while(L <= mid) tmp[cnt++] = a[L++];
while(R <= r){
ans[a[R].id] += cal(a[R].z);
tmp[cnt++] = a[R++];
}
for(int i=0; i<cnt; ++i){
clr(tmp[i].z);
a[l+i] = tmp[i];
}
}
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].id=i;
sort(a+1, a+1+n, cmp);
cdq(1,n);
for(int i=n-1; i; --i){
if(a[i].x==a[i+1].x && a[i].y==a[i+1].y && a[i].z == a[i+1].z)
ans[a[i].id] = max(ans[a[i].id], ans[a[i+1].id]);
}
for(int i=1; i<=n; ++i) ++tot[ans[i]];
for(int i=0; i<n; ++i) printf("%d\n",tot[i]);
return 0;
}