12
5
2015
0

3262: 陌上花开

3262: 陌上花开

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
 

 

 

 

CDQ分治

 

先将花(下面说成点,三个属性分别看做a,b,c)

按a为第一关键字,b为第二关键字,c为第三关键字排序

那么对于每个点P,在P之前的点I都满足 I.a <= P.a

所以只需要求满足 I.b <= P.b 且 I.c <= P.c 的点I的个数

那么 每个满足条件的点I 对 点P答案的贡献为1

定义一个过程solve(L, R) 求出[L, R]中的点的相互贡献值

 

对于当前solve(L, R)

我们将点分成两堆,分别求[L, mid]和[mid + 1, R]中的点的相互贡献值

现在考虑求[L, mid]中的点对[mid + 1, R]中的点的贡献

将[L, R]中的点按b为第一关键字重新排序(建议用归并排序)

那么现在对于[mid + 1, R]中的点P,

若P前有一点Q满足 在点集[L, mid]中 且 Q.c<=P.c

则Q对P有贡献值1

然后采用一个数据结构(你可以用 线段树 或者 树状数组)

将排序后的点I按顺序 更新(在I.c位置加入) 或 询问(查询I.c位置的前缀和) 贡献值

([L, mid]点集中的点用于更新某一位置的贡献值,

        [mid+1, R]点集中的点用于询问贡献值并加入答案)

即solve(L, R)完成。。。

 

或许你看不懂上面的一小段(其实wy回头看时也是看不懂的T_T)

所以我们举一个例子

现在有点(1,3,2),(2,1,1),(2,2,3),(3,3,3)

下面是模拟过程。。。

 solve(1,4)

   solve(1,2)

     solve(1,1)    ----没有更新答案

     solve(2,2)    ----没有更新答案

     (2,1,1) 在数据结构中查询1位置的贡献前缀和,没有更新答案

     (1,3,2) 在2位置添加1个贡献值,不查询贡献

   solve(3,4)

     solve(3,3)    ----没有更新答案

     solve(4,4)    ----没有更新答案

     (2,2,3) 在新数据结构3位置添加1个贡献值,不查询贡献

     (3,3,3) 查询3位置的贡献前缀和,点4 的答案 +1

 (2,1,1) 在新数据结构中1位置添加1个贡献值,不查询贡献

 (2,2,3) 查询3位置的贡献前缀和,点3 的答案 +1

 (1,3,2) 在2位置添加1个贡献值,不查询贡献

 (3,3,3) 查询3位置的贡献前缀和,点4 的答案 +2

以上就是模拟过程。。。

 

(⊙o⊙)…鉴于wy的语文水平较差T_T,还没有看懂的童鞋请看程序

#include <cstdio>
#include <algorithm>
using namespace std;
const int MaxN = 100010;
const int MaxM = 200010;
int N, S;
int sum[MaxN],L[MaxM];
struct point{
	int a, b, c, key, s;
	inline point (int x = 0, int y = 0, int z = 0, int w = 0, int cnt = 0){
		a = x; b = y; c = z; key = w; s = cnt;
	}
	inline bool operator == (const point &Q){
		return a == Q.a && b == Q.b && c == Q.c;
	}
}p[MaxN], q[MaxN];
inline bool cmp(const point &a, const point &b){
	return a.a < b.a || a.a == b.a && a.b < b.b || a.a == b.a && a.b == b.b && a.c < b.c;
}
inline int lowbit(int x){
	return x & -x;
}
inline void New(int x){
	for (int i = x; i <= S; i += lowbit(i))
	    if (sum[i]) sum[i]=0;
	    else break;
}
inline void Insert(int x, int k){
	for (int i = x; i <= S; i += lowbit(i))
	    sum[i] += k;
}
inline int Query(int x){
	int s=0;
	for (int i = x; i>0 ; i -= lowbit(i))
	    s += sum[i];
	return s;
}
inline void solve(int l, int r){
	if (l == r) return; 
	int mid = l + r >> 1;
	solve(l, mid), solve(mid + 1, r);
	int t1 = l, t2 = mid + 1;
	for (int i = l; i <= r; ++i)
	    if (t1 <= mid && p[t1].b <= p[t2].b || t2 > r){
	    	q[i] = p[t1++];
	    	Insert(q[i].c,q[i].s);
		}
		else {
			q[i] = p[t2++];
			q[i].key += Query(q[i].c);
		}
	for (int i = l; i <= r; ++i)
        p[i] = q[i], New(p[i].c);
}
int main(){
    scanf("%d%d", &N, &S);
    for (int i = 1; i <= N; ++i)
    	scanf("%d%d%d", &p[i].a, &p[i].b, &p[i].c);
    sort(p + 1, p + N + 1, cmp);
    int m = 0;
    for (int i = 1; i <= N; ++i){
        if (!m || !(q[m] == p[i])) q[++m] = p[i];
        ++q[m].s;
	}
    for (int i =1; i <= m; ++i)
        p[i] = q[i];
    solve(1, m);
    for (int i = 1; i <= m; ++i)
        L[p[i].key + p[i].s - 1] += p[i].s;
    for (int i = 0; i < N; ++i)
        printf("%d\n",L[i]); 
} 
 
Ps:注意到这道题有重复的点,去重,重复点的贡献值增加即可。。。
Category: BZOJ | Tags: bzoj 分治 bit | Read Count: 452

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com