## [ZeroJudge c571. 三維偏序問題](https://zerojudge.tw/ShowProblem?problemid=c571)
CDQ分治題,但我不要CDQ分治。
雖然CDQ分治的時間複雜度為$O(n \log^2 n)$,空間是好好的$O(n)$,但我不擅長分治。
所以我決定用動態開點線段樹直接模擬,時間也是$O(n \log^2 n)$,而空間則是$O(n \log^2 n)$。
~~之後我發現我被卡常了,所以我就用快讀快寫硬卡過了ww~~
我的動態開點線段樹是寫偽指標,~~但是是指標型的偽指標~~,扣當參考就好,很醜。
:::spoiler code:
```cpp=
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt")
#include <bits/stdc++.h>
#include <unistd.h>
#define F first
#define S second
#define lowbit(x) ((x) & -(x))
using namespace std;
using i64 = long long;
using u32 = uint32_t;
using p2i = pair<int, int>;
using p2l = pair<i64, i64>;
inline namespace fake_pointer_impl {
constexpr u32 blk_lg = 12;
constexpr u32 blk_sz = 1 << blk_lg;
constexpr u32 blk_mod = blk_sz - 1;
template <typename Tp>
struct fake_pointer {
static inline vector<Tp*> pool;
static inline u32 cnt = 0;
int32_t id;
fake_pointer() :id(-1) {}
fake_pointer(nullptr_t) :id(-1) {}
fake_pointer(const fake_pointer&) = default;
fake_pointer(fake_pointer&&) = default;
inline fake_pointer&
operator=(nullptr_t)
{ return (id = -1), *this; }
inline fake_pointer&
operator=(const fake_pointer&) = default;
inline fake_pointer&
operator=(fake_pointer&&) = default;
inline Tp&
operator*() const
{ return pool[id >> blk_lg][id & blk_mod]; }
inline Tp*
operator->() const
{ return &(this->operator*()); }
explicit operator bool() const
{ return id >= 0; }
operator Tp*() const
{ return (this->operator->()); }
static inline fake_pointer
single_alloc() {
if (!(cnt & blk_mod)) pool.emplace_back(static_cast<Tp*>(::operator new(sizeof(Tp) * blk_sz)));
return fake_pointer(cnt++);
}
private:
fake_pointer(int32_t _id) :id(_id) {}
};
};
inline namespace dont_open_segtree_impl {
struct dont_open_segtree_node {
u32 cnt;
fake_pointer<dont_open_segtree_node> p_l, p_r;
dont_open_segtree_node() :cnt(0), p_l(), p_r() {}
};
struct dont_open_segtree {
u32 n;
fake_pointer<dont_open_segtree_node> root;
using node_pointer = fake_pointer<dont_open_segtree_node>;
dont_open_segtree() :n(0), root() {}
dont_open_segtree(u32 _n) :n(_n), root() {}
inline void
modify(u32 pos, u32 val) {
return modify(0, n, pos, val, root);
}
inline u32
query(u32 ql, u32 qr) {
return query(0, n, ql, qr, root);
}
private:
inline void
modify(u32 l, u32 r, u32 pos, u32 val, node_pointer& p) {
if (!p) {
p = node_pointer::single_alloc();
::new(static_cast<dont_open_segtree_node*>(p)) dont_open_segtree_node();
}
p->cnt += val;
if (r - l == 1) return;
u32 m = (l + r) >> 1;
return ((pos < m) ? modify(l, m, pos, val, p->p_l) : modify(m, r, pos, val, p->p_r));
}
inline u32
query(u32 l, u32 r, u32 ql, u32 qr, node_pointer p) {
if (!p) return 0;
if (ql <= l && r <= qr) return p->cnt;
u32 m = (l + r) >> 1;
if (qr <= m) return query(l, m, ql, qr, p->p_l);
if (ql >= m) return query(m, r, ql, qr, p->p_r);
return query(l, m, ql, qr, p->p_l) + query(m, r, ql, qr, p->p_r);
}
};
struct dont_open_segtree_2D_node {
dont_open_segtree seg;
fake_pointer<dont_open_segtree_2D_node> p_l, p_r;
dont_open_segtree_2D_node() = default;
dont_open_segtree_2D_node(u32 _n) :seg(_n), p_l(), p_r() {}
};
struct dont_open_segtree_2D {
u32 n;
fake_pointer<dont_open_segtree_2D_node> root;
using node_pointer = fake_pointer<dont_open_segtree_2D_node>;
dont_open_segtree_2D(u32 _n) :n(_n), root() {}
inline void
modify(u32 pos_x, u32 pos_y, u32 val) {
return modify(0, n, pos_x, pos_y, val, root);
}
inline u32
query(u32 ql_x, u32 qr_x, u32 ql_y, u32 qr_y) {
return query(0, n, ql_x, qr_x, ql_y, qr_y, root);
}
private:
inline void
modify(u32 l, u32 r, u32 pos_x, u32 pos_y, u32 val, node_pointer& p) {
if (!p) {
p = node_pointer::single_alloc();
::new(static_cast<dont_open_segtree_2D_node*>(p)) dont_open_segtree_2D_node(n);
}
(p->seg).modify(pos_y, val);
if (r - l == 1) return;
u32 m = (l + r) >> 1;
return ((pos_x < m) ? modify(l, m, pos_x, pos_y, val, p->p_l) : modify(m, r, pos_x, pos_y, val, p->p_r));
}
inline u32
query(u32 l, u32 r, u32 ql_x, u32 qr_x, u32 ql_y, u32 qr_y, node_pointer p) {
if (!p) return 0;
if (ql_x <= l && r <= qr_x) return (p->seg).query(ql_y, qr_y);
u32 m = (l + r) >> 1;
if (qr_x <= m) return query(l, m, ql_x, qr_x, ql_y, qr_y, p->p_l);
if (ql_x >= m) return query(m, r, ql_x, qr_x, ql_y, qr_y, p->p_r);
return query(l, m, ql_x, qr_x, ql_y, qr_y, p->p_l) + query(m, r, ql_x, qr_x, ql_y, qr_y, p->p_r);
}
};
};
inline namespace fastIO {
constexpr u32 Ibuf_size = 1 << 17;
struct In {
char Ibuf[Ibuf_size], *Il, *Ir, Ic;
In() :Il(Ibuf), Ir(Ibuf), Ic() {}
inline void
load() {
Ir = ((Il = Ibuf) + fread(Ibuf, 1, Ibuf_size, stdin));
}
#define get_char() (((Il == Ir) && (load(), (Il == Ir))) ? -1 : *Il++)
inline In&
operator>>(u32& __x) {
while (!isdigit(Ic = get_char()));
__x = Ic & 15;
while (isdigit(Ic = get_char()))
(__x *= 10) += Ic & 15;
return *this;
}
} static cIn;
constexpr u32 Obuf_size = 1 << 17;
struct Out {
char Obuf[Obuf_size], *Ol, *Or;
Out() :Ol(Obuf), Or(Obuf + Obuf_size) {}
~Out() { flush(); }
inline void
flush() {
write(1, Obuf, Ol - Obuf);
Ol = Obuf;
}
inline Out&
operator<<(char __c) {
if (Ol == Or) flush();
*Ol++ = __c;
return *this;
}
inline Out&
operator<<(u32 __x) {
static char num_buf[8];
static u32 len;
len = 0;
do {
num_buf[len++] = (__x % 10) ^ 48;
} while (__x /= 10);
if (Ol + len >= Or) flush();
while (len--) *Ol++ = num_buf[len];
return *this;
}
} static cOut;
};
#define cin cIn
#define cout cOut
int main() {
u32 n; cin >> n;
vector<tuple<u32, u32, u32>> v(n);
vector<u32> ans(n, 0), idx(n);
iota(idx.begin(), idx.end(), 0);
dont_open_segtree_2D sgt(n);
for (int i = 0; i < n; i++) {
cin >> get<0>(v[i]) >> get<1>(v[i]) >> get<2>(v[i]);
}
sort(idx.begin(), idx.end(), [&v](const auto& a, const auto& b) -> bool {
return (get<0>(v[a]) > get<0>(v[b])) || ((get<0>(v[a]) == get<0>(v[b])) && (get<1>(v[a]) < get<1>(v[b])));
});
for (auto i : idx) {
ans[i] = sgt.query(get<1>(v[i]), n, get<2>(v[i]), n);
sgt.modify(get<1>(v[i]) - 1, get<2>(v[i]) - 1, 1);
}
for (auto i : ans) cout << i << '\n';
return 0;
}
```
:::
:::spoiler upd : CDQ分治 AC code:
```cpp=
#include <bits/stdc++.h>
using namespace std;
pair<int, pair<int, int>> points[100000];
int id[100000], ans[100000], fwt[100002], N;
void modify(int x, int val) {
for (; x <= N + 1; x += (x & -x)) fwt[x] += val;
}
int query(int cnt) {
int ret = 0;
for (; cnt; cnt -= (cnt & -cnt)) ret += fwt[cnt];
return ret;
}
bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
return a.first > b.first || (a.first == b.first && a.second < b.second);
}
void cdq(int l, int r) {
static int tmp[100000];
if (r - l == 1) return;
int m = (l + r) >> 1;
cdq(l, m), cdq(m, r);
int i = m - 1, j = r - 1, idx = r;
for (; i >= l || j >= m; ) {
if (i < l) {
tmp[--idx] = id[j];
modify(points[id[j]].second.second, 1);
--j;
continue;
}
if (j < m) {
tmp[--idx] = id[i];
ans[id[i]] += query(N) - query(points[id[i]].second.second);
--i;
continue;
}
if (cmp(points[id[i]].second, points[id[j]].second)) {
tmp[--idx] = id[i];
ans[id[i]] += query(N) - query(points[id[i]].second.second);
--i;
continue;
}
else {
tmp[--idx] = id[j];
modify(points[id[j]].second.second, 1);
--j;
continue;
}
}
for (idx = r; idx-- > m; ) {
modify(points[id[idx]].second.second, -1);
}
copy(tmp + l, tmp + r, id + l);
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin >> N;
for (int i = 0; i < N; i++) {
cin >> points[i].first >> points[i].second.first >> points[i].second.second;
id[i] = i;
}
sort(id, id + N, [&](const auto a, const auto b) -> bool {
return points[a].first < points[b].first || (points[a].first == points[b].first && points[a].second > points[b].second);
});
cdq(0, N);
for (int i = 0; i < N; i++) cout << ans[i] << '\n';
return 0;
}
```
:::