[BZOJ 3262] 陌上花开
Description
有 \(N\) 朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花 A 比另一朵花 B 要美丽,当且仅当 \(s_A\ge s_B,c_A\ge c_B ,m_A\ge m_B\)。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为 \(N,K\),分别表示花的数量和最大属性值。
以下 \(N\) 行,每行三个整数 \(s_i, c_i, m_i~(1 \le s_i, c_i, m_i \le 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 \le N \le 100000, 1 \le K \le 200000\)
Solution
CDQ分治模板题。
首先排序消去第一维,分治时保证 \([l,mid]\) 的第二维不大于 \([mid+1,r]\) 的第二维,第三维用树状数组统计。
Code
#include <cstdio>
#include <algorithm>
const int N = 100005;
struct Node {
int a, b, c, n, v;
bool operator < (const Node &rhs) const {
return a == rhs.a ? (b == rhs.b ? c < rhs.c : b < rhs.b) : a < rhs.a;
}
} a[N], b[N];
int n, m = 1, K, ans[N], sum[N << 1];
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
void clear(int x) {
while (x <= K) {
if (!sum[x]) break;
sum[x] = 0, x += x & (-x);
}
}
void update(int x, int y) {
while (x <= K) sum[x] += y, x += x & (-x);
}
int query(int x) {
int res = 0;
while (x) res += sum[x], x -= x & (-x);
return res;
}
void solve(int l, int r) {
if (l >= r) return;
int mid = (l + r) >> 1, p = l, q = mid + 1, t = 0;
solve(l, mid), solve(mid + 1, r);
while (p <= mid && q <= r) {
if (a[p].b <= a[q].b) update(a[p].c, a[p].n), b[t++] = a[p++];
else a[q].v += query(a[q].c), b[t++] = a[q++];
}
if (p <= mid) {
for (int i = l; i < p; ++i) clear(a[i].c);
while (p <= mid) b[t++] = a[p++];
} else if (q <= r) {
while (q <= r) a[q].v += query(a[q].c), b[t++] = a[q++];
for (int i = l; i <= mid; ++i) clear(a[i].c);
}
for (int i = 0; i < t; ++i) a[l + i] = b[i];
}
int main() {
n = read(), K = read();
for (int i = 1; i <= n; ++i) a[i].a = read(), a[i].b = read(), a[i].c = read(), a[i].n = 1;
std::sort(a + 1, a + n + 1);
for (int i = 2; i <= n; ++i)
if (a[i - 1] < a[i]) a[++m] = a[i]; else ++a[m].n;
solve(1, m);
for (int i = 1; i <= m; ++i) ans[a[i].v + a[i].n - 1] += a[i].n;
for (int i = 0; i < n; ++i) printf("%d\n", ans[i]);
return 0;
}