欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[bzoj3262]陌上花开 三维偏序 cdq分治+树状数组

程序员文章站 2022-03-03 09:05:05
...

3262: 陌上花开

Time Limit: 20 Sec  Memory Limit: 256 MB
[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

1 <= N <= 100,000, 1 <= K <= 200,000

Source

这道题很明显是一道三维偏序的题
sort套cdq套树状数组
外围按s排序,c为第二关键字,m为第三关键字
第二层按c排序,m为第二关键字
这道题要输出所有的花的等级数,有的等级是没有花的,注意,同一个等级的花比和它完全相同的花美丽
这道题说明我是个zz,i+1写成i-1,要先找完再统计
#include<algorithm>
#include<cstdio>
const int M = 200000 + 5;
int N,n,K,c[M],ans[M],cnt;
struct data{
	int s,c,m,num,ans;
}a[M],b[M];
bool cmp( data a, data b ){
	if( a.s == b.s && a.c == b.c ) return a.m < b.m;
	if( a.s == b.s ) return a.c < b.c;
	return a.s < b.s;
}
bool cmp2( data a, data b ){ return a.c == b.c ? a.m < b.m : a.c < b.c; }
void modify( int k, int v ){ for( int i = k; i <= K; i += i&-i ) c[i] += v; }
int query( int k ){
	int res = 0;
	for( int i = k; i; i -= i&-i ) res += c[i];
	return res;
}
void cdq( int l, int r ){
	if( l == r ) return ;
	int mid = (l+r)>>1; cdq(l,mid); cdq(mid+1,r);
	std::sort(b+l,b+mid+1,cmp2); std::sort(b+mid+1,b+r+1,cmp2);
	int t1 = l, t2 = mid+1;
	while( t2 <= r ){
		while( t1 <= mid && b[t1].c <= b[t2].c ){
			modify( b[t1].m, b[t1].num ); t1++;
		}
		b[t2].ans += query(b[t2].m); t2++;
	}
	for( int i = l; i < t1; i++ ) modify( b[i].m, -b[i].num );
}
int main(){
	scanf("%d%d", &N, &K);
	for( int i = 1; i <= N; i++ ) scanf("%d%d%d", &a[i].s, &a[i].c, &a[i].m);
	std::sort(a+1,a+N+1,cmp);
	for( int i = 1; i <= N; i++ ){
		cnt++;
		if( a[i].s != a[i+1].s || a[i].c != a[i+1].c || a[i].m != a[i+1].m ){
			b[++n] = a[i]; b[n].num = cnt; cnt = 0;
		}
	}
	cdq(1,n);
	for( int i = 1; i <= n; i++ ) ans[b[i].ans+b[i].num] += b[i].num;
	for( int i = 1; i <= N; i++ ) printf("%d\n", ans[i]);
	return 0;
}
总结
边界的问题,t1在最后比队尾要大1
统计时注意是队尾统计还是队首统计
bzoj200题,我也是够狼狈的,感到很空虚