BZOJ3262 陌上花开 —— 三维偏序 CDQ分治

时间:2023-03-10 04:05:21
BZOJ3262 陌上花开 —— 三维偏序 CDQ分治

题目链接:https://vjudge.net/problem/HYSBZ-3262

3262: 陌上花开

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 3188  Solved: 1472
[Submit][Status][Discuss]

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分治。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 2e5+; struct node
{
int x, y, z, s, id;
bool operator<(const node& b)const{
if(x==b.x){
if(y==b.y) return z<b.z;
return y<b.y;
}
return x<b.x;
}
};
node a[MAXN], b[MAXN]; int n, k, c[MAXN];
int lowbit(int x) {return x&(-x);}
void add(int x, int val) {for(int i=x;i<=k;i+=lowbit(i)) c[i]+=val;}
int sum(int x) {int ret=; for(int i=x;i>;i-=lowbit(i))ret+=c[i]; return ret;} // 第一维排序,第二维CDQ,第三维树状数组
void CDQ(int l, int r)
{
if(l==r) return; int mid = (l+r)/;
CDQ(l, mid); CDQ(mid+, r);
int p1 = l, p2 = mid+;
for(int i = l; i<=r; i++) //按y排序,归并排序
{
//必须是:a[p1].y<=a[p2].y,不能少了==这个判断,因为当a[p1].y==a[p2].y时,必定p1排在前面,因为p1的z比p2小
if(p2>r||(p1<=mid&&a[p1].y<=a[p2].y)) b[i] = a[p1++];
else b[i] = a[p2++];
}
//此时y按从小到大排序,当y相等时,x小的排前面。
for(int i = l; i<=r; i++)
{
a[i] = b[i]; //b为a归并排序时的临时存储,应把值放回到a里
if(a[i].id<=mid) add(a[i].z, ); //当x小于等于mid,则把它的z加入到树状数组中,被别人统计
else a[i].s += sum(a[i].z); //当x大于mid时,拿自己的z到线段树中统计
}
for(int i = l; i<=r; i++) //撤回在线段树中的操作
if(a[i].id<=mid) add(a[i].z, -);
} int ans[MAXN];
int main()
{
while(scanf("%d%d", &n,&k)!=EOF)
{
for(int i = ; i<=n; i++)
{
scanf("%d%d%d", &a[i].x,&a[i].y,&a[i].z);
a[i].s = ;
}
sort(a+,a++n);
memset(c, , sizeof(c));
for(int i = ; i<=n; i++)
a[i].id = i;
CDQ(,n); memset(ans, , sizeof(ans));
for(int i = n-; i>=; i--) //一样的点,选值最大的
if(a[i].x==a[i+].x&&a[i].y==a[i+].y&&a[i].z==a[i+].z)
a[i].s = a[i+].s; for(int i = ; i<=n; i++)
ans[a[i].s]++;
for(int i = ; i<n; i++)
printf("%d\n", ans[i]);
}
}