Mayor's posters
阿新 • • 發佈:2022-03-23
線段樹+離散化
將海報覆蓋的區間線上段樹中進行標記,最後統計存在於樹中的海報型別
由於本題的資料範圍比較大,需要對座標進行離散化。之後再遞迴的遍歷每一個節點,將存在的標記存放到set中,最終set中元素的數量就是海報的型別
注意:
- 離散化後,區間之間的相對寬度會發生變化,比如[1, 10000]離散化後,變成[1,2],顯然後者的覆蓋範圍要遠小於前者。這點要注意,所以格外新增\(l+1\)和\(r+1\)
- 除了建樹的過程外,對於訪問子節點的操作都需要下放懶標記,所以在修改和詢問時要
push_down
#include <iostream> #include <algorithm> #include <set> #include <vector> using namespace std; typedef pair<int, int> PII; constexpr int N = 2e5 + 100; struct Node { int l, r; int t; } tr[N * 4]; int n, g[N], cnt; vector<PII> v(N); set<int> se; inline int get(int x) { return lower_bound(g + 1, g + cnt + 1, x) - g; } void build(int u, int l, int r) { tr[u] = {l, r}; if (l == r) return; int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); } inline void push_down(int u) { int &t = tr[u].t; if (t) tr[u << 1].t = tr[u << 1 | 1].t = t; t = 0; } void modify(int u, int l, int r, int t) { if (tr[u].l >= l && tr[u].r <= r) tr[u].t = t; else { push_down(u); int mid = tr[u].l + tr[u].r >> 1; if (l <= mid) modify(u << 1, l, r, t); if (r > mid) modify(u << 1 | 1, l, r, t); } } void count(int u, int l, int r) { // printf("%d %d %d %d\n", u, tr[u].t, l, r); if (tr[u].t) se.insert(tr[u].t); if (l == r) return; push_down(u); int mid = l + r >> 1; count(u << 1, l, mid), count(u << 1 | 1, mid + 1, r); } int main() { int _T; scanf("%d", &_T); while (_T --) { scanf("%d", &n); v.clear(); se.clear(); cnt = 0; for (int i = 0; i < n; i++) { int l, r; scanf("%d%d", &l, &r); v.push_back({l, r}); g[++cnt] = l, g[++cnt] = r, g[++cnt] = r + 1, g[++cnt] = l + 1; } sort(g + 1, g + cnt + 1); cnt = unique(g + 1, g + cnt + 1) - g; build(1, 1, cnt); for (int i = 0; i < v.size(); i++) { auto [l, r] = v[i]; l = get(l), r = get(r); modify(1, l, r, i + 1); } count(1, 1, cnt); printf("%zd\n", se.size()); } return 0; }
set非離散化
從後往前,將當前海報覆蓋的範圍的點全部刪除,列舉的區間存在部分端點在set中,代表該海報沒有被完全覆蓋
注意:假如要刪除的區間是最右邊的,那麼當區間內的元素會始終小於區間右邊端點,此時while
迴圈不會停止,所以要格外假如r+1
這個點。
#include <iostream> #include <algorithm> #include <set> #include <cstdio> #include <utility> using namespace std; typedef pair<int, int> PII; const int N = 1e5 + 1000; set<int> se; PII q[N]; int n; int main() { int _T; scanf("%d", &_T); while (_T --) { int res = 0; se.clear(); scanf("%d", &n); for (int i = 1; i <= n; i++) { int & l = q[i].first, &r = q[i].second; scanf("%d%d", &l, &r); se.insert(l), se.insert(r), se.insert(r + 1); } for (int i = n; i; i--) { int l = q[i].first, r = q[i].second; auto t = se.lower_bound(l); if (*t <= r) res++; while (*t <= r) { se.erase(t); t = se.lower_bound(l); } } printf("%d\n", res); } return 0; }