2815. 三维偏序

题目链接

2815. 三维偏序

给定 \(n\) 个元素(编号 \(1 \sim n\)),其中第 \(i\) 个元素具有 \(a_i,b_i,c_i\) 三种属性。

\(f(i)\) 表示满足以下 \(4\) 个条件:

  1. \(a_j \le a_i\)
  2. \(b_j \le b_i\)
  3. \(c_j \le c_i\)
  4. \(j \neq i\)

\(j\) 的数量。

对于 \(d \in [0,n)\),求满足 \(f(i) = d\)\(i\) 的数量。

输入格式

第一行两个整数 \(n,k\),表示元素数量和最大属性值。

接下来 \(n\) 行,其中第 \(i\) 行包含三个整数 \(a_i ,b_i,c_i\),分别表示第 \(i\) 个元素的三个属性值。

输出格式

\(n\) 行,每行输出一个整数,其中第 \(d+1\) 行的整数表示满足 \(f(i) = d\)\(i\) 的数量。

数据范围

\(1 \le n \le 10^5\),
\(1 \le a_i,b_i,c_i \le k \le 2 \times 10^5\)

输入样例:

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

cdq分治主要用来解决三维偏序问题,其作用主要是用来以较小的空间复杂度取代某些数据结构
例如本题如果数据范围较小的话可以用二维树状数组来求解,即先将第一个属性排序,然后其他两个属性用二维树状数组求解即可,但本题空间复杂度不允许

本题得用cdq分治求解:先将第一个属性排序,然后在此基础上对第二个属性进行归并排序,同时在第二个属性排序的过程中用树状数组维护第三个属性

  • 时间复杂度:\(O(nlog^2n)\)

代码

// Problem: 三维偏序
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2817/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=2e5+5;
int n,k,tr[N],res[N];
struct A
{
	int a,b,c,s,res;
	bool operator<(const A &o)const
	{
		if(a!=o.a)return a<o.a;
		if(b!=o.b)return b<o.b;
		return c<o.c;
	}
	bool operator==(const A &o)const
	{
		return a==o.a&&b==o.b&&c==o.c;
	}
}a[N],b[N];
void add(int x,int y)
{
	for(;x<N;x+=x&-x)tr[x]+=y;
}
int ask(int x)
{
	int res=0;
	for(;x;x-=x&-x)res+=tr[x];
	return res;
}
void merge_sort(int l,int r)
{
	if(l>=r)return ;
	int mid=l+r>>1;
	merge_sort(l,mid),merge_sort(mid+1,r);
	int i=l,j=mid+1,k=0;
	while(i<=mid&&j<=r)
		if(a[i].b<=a[j].b)add(a[i].c,a[i].s),b[++k]=a[i++];
		else
			a[j].res+=ask(a[j].c),b[++k]=a[j++];
	while(i<=mid)add(a[i].c,a[i].s),b[++k]=a[i++];
	while(j<=r)a[j].res+=ask(a[j].c),b[++k]=a[j++];
	for(int i=l;i<=mid;i++)add(a[i].c,-a[i].s);
	for(int i=l,j=1;j<=k;j++,i++)a[i]=b[j];
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i].a>>a[i].b>>a[i].c,a[i].s=1;
    sort(a+1,a+1+n);
    int k=2;
    for(int i=2;i<=n;i++)
    	if(a[i]==a[k-1])a[k-1].s++;
    	else
    		a[k++]=a[i];
    merge_sort(1,k-1);
    for(int i=1;i<k;i++)res[a[i].res+a[i].s-1]+=a[i].s;
    for(int i=0;i<n;i++)cout<<res[i]<<'\n';
    return 0;
}
posted @ 2022-10-11 11:44  zyy2001  阅读(38)  评论(0编辑  收藏  举报