題意:有n朵花,每朵花有3個屬性,若一朵花比另一朵花美麗,當且僅當這朵花的三個屬性均不小於另一朵花。一朵花的美麗度等於這朵花比其他多少朵花要美麗。
求美麗度分別爲0~n-1的花各有多少朵。
Sol:事實上就是三維偏序。一句話:一維排序,二維CDQ分治,三維樹狀數組。
How do they work?
首先根據x座標排序,接着對y,z座標CDQ分治。
定義Solve(l,r)爲處理l~r一段的美麗度。
令mid=(l+r)/2,我們首先進行Solve(l,mid),Solve(mid+1,r).假設我們處理完之後兩端的y值均從大到小有序。
我們處理前一段對後一段的影響:按照線性合併的思想,若對後一段進行合併時,則利用樹狀數組更新後一段的答案。否則更新樹狀數組。
這樣我們能保證Solve(l,r)能正確的更新答案,且使得y一維從小到大有序。另外我們使用樹狀數組,是爲了維護z這一維。
時間複雜度O(nlog^2n).
爲了處理相同的影響,我事實上將x和y相同的部分當做一段整體處理。
Code:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()));
int tmp = c - '0';
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - '0';
return tmp;
}
char buf[600010], *o = buf;
#define _putchar(c) *o++ = c
inline void output(int x) {
static int stack[10];
if (!x)
*o++ = 48;
else {
int top = 0;
for(; x; stack[++top] = x % 10, x /= 10);
for(int i = top; i >= 1; --i)
*o++ = 48 + stack[i];
}
}
#define N 100010
struct Case {
int x, y, z;
void read() {
x = getint(), y = getint(), z = getint();
}
bool operator < (const Case &B) const {
return x < B.x || (x == B.x && y < B.y);
}
}S[N], tmp[N];
int left[N], right[N], cnt, seq[N], _seq[N];
#define K 200010
int lim;
int A[K], now[K], tclock;
int ask(int x, int tclock) {
int res = 0;
for(; x; x -= x & -x) {
if (now[x] != tclock) {
A[x] = 0;
now[x] = tclock;
}
res += A[x];
}
return res;
}
void modify(int x, int add, int tclock) {
for(; x <= lim; x += x & -x) {
if (now[x] != tclock) {
A[x] = 0;
now[x] = tclock;
}
A[x] += add;
}
}
int ans[N];
void Divide(int l, int r) {
register int i, j, k, p;
if (l == r) {
++tclock;
for(i = left[seq[l]]; i <= right[seq[l]]; ++i)
modify(S[i].z, 1, tclock);
for(i = left[seq[l]]; i <= right[seq[l]]; ++i)
ans[i] += ask(S[i].z, tclock);
return;
}
int mid = (l + r) >> 1;
Divide(l, mid);
Divide(mid + 1, r);
++tclock;
i = l, j = mid + 1, k = l;
while(i <= mid && j <= r) {
if (S[left[seq[i]]].y <= S[left[seq[j]]].y) {
_seq[k++] = seq[i];
for(p = left[seq[i]]; p <= right[seq[i]]; ++p)
modify(S[p].z, 1, tclock);
++i;
}
else {
_seq[k++] = seq[j];
for(p = left[seq[j]]; p <= right[seq[j]]; ++p)
ans[p] += ask(S[p].z, tclock);
++j;
}
}
while(i <= mid)
_seq[k++] = seq[i++];
while(j <= r) {
for(p = left[seq[j]]; p <= right[seq[j]]; ++p)
ans[p] += ask(S[p].z, tclock);
_seq[k++] = seq[j++];
}
memcpy(seq + l, _seq + l, sizeof(int) * (r - l + 1));
}
int nums[N];
int main() {
//freopen("tt.in", "r", stdin);
int n = getint();
lim = getint();
register int i, j;
for(i = 1; i <= n; ++i)
S[i].read();
std::sort(S + 1, S + n + 1);
for(i = 1; i <= n; ) {
for(j = i; S[j].x == S[j + 1].x && S[j].y == S[j + 1].y; ++j);
left[++cnt] = i, right[cnt] = j;
i = j + 1;
}
for(i = 1; i <= cnt; ++i)
seq[i] = i;
Divide(1, cnt);
for(i = 1; i <= n; ++i)
++nums[ans[i]];
for(i = 1; i <= n; ++i) {
output(nums[i]);
_putchar('\n');
}
fwrite(buf, 1, o - buf, stdout);
return 0;
}