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

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
#include
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题,我也是够狼狈的,感到很空虚

你可能感兴趣的:(树状数组,bzoj,cdq分治)