CF793F Julia the snail 題解
阿新 • • 發佈:2021-07-02
一、題目:
二、思路:
這道題的官方題解是分塊,在這裡提供一種吉司機線段樹的做法。
設所有的傳送門為二元組 \((l,r)\),詢問為二元組 \((a,b)\)。吉司機線段樹上的葉子結點 \(i\) 儲存當詢問的 \(a=i\) 時的答案。
考慮將所有的詢問按照右端點從小到大排序。我們維護一個指標 \(p\),遇到一個新的詢問,就將 \(p\) 向右移動到新的詢問的右端點。並做以下處理:
對於指標移動過程中遇到的所有 \(r\),那麼對於線段樹下標區間為 \([1,l]\) 中的、所有大於 \(l\) 的數,將它的值變為 \(r\)。
三、程式碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define FILEIN(s) freopen(s, "r", stdin) #define FILEOUT(s) freopen(s, "w", stdout) #define mem(s, v) memset(s, v, sizeof s) inline int read(void) { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return f * x; } const int MAXN = 100005, INF = 1e8; int n, m, pre[MAXN], Q, ans[MAXN]; struct Query { int l, r, id; inline friend bool operator <(const Query &a, const Query &b) { return a.r < b.r; } }q[MAXN]; namespace Segment_Tree_Beat { #define lson (o << 1) #define rson (o << 1 | 1) int maxx[MAXN << 2], sec[MAXN << 2]; int L[MAXN << 2], R[MAXN << 2]; int tag1[MAXN << 2], tag2[MAXN << 2]; inline void pushup(int o) { if (maxx[lson] == maxx[rson]) { maxx[o] = maxx[lson]; sec[o] = max(sec[lson], sec[rson]); } else if (maxx[lson] > maxx[rson]) { maxx[o] = maxx[lson]; sec[o] = max(sec[lson], maxx[rson]); } else { maxx[o] = maxx[rson]; sec[o] = max(sec[rson], maxx[lson]); } } void build(int o, int l, int r) { L[o] = l; R[o] = r; tag1[o] = tag2[o] = INF; if (l == r) { maxx[o] = l; sec[o] = -1; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(o); } inline void change(int o, int v1, int v2) { if (maxx[o] < v1) return; maxx[o] = v2; if (v1 <= tag2[o]) { tag1[o] = min(tag1[o], v1); tag2[o] = v2; } } inline void pushdown(int o) { if (tag1[o] != INF) { change(lson, tag1[o], tag2[o]); change(rson, tag1[o], tag2[o]); tag1[o] = tag2[o] = INF; } } inline void update(int o, int ql, int qr, int v1, int v2) { if (v1 > maxx[o]) return; if (ql <= L[o] && R[o] <= qr && v1 > sec[o]) { change(o, v1, v2); return; } pushdown(o); int mid = (L[o] + R[o]) >> 1; if (ql <= mid) update(lson, ql, qr, v1, v2); if (qr > mid) update(rson, ql, qr, v1, v2); pushup(o); } inline int query(int o, int q) { if (L[o] == R[o]) return maxx[o]; pushdown(o); int mid = (L[o] + R[o]) >> 1; if (q <= mid) return query(lson, q); return query(rson, q); } } inline void modify(int p) { if (!pre[p]) return; Segment_Tree_Beat::update(1, 1, pre[p], pre[p], p); } int main() { n = read(); m = read(); for (int i = 1; i <= m; ++ i) { int l = read(), r = read(); if (l == r) continue; pre[r] = l; } Q = read(); for (int i = 1; i <= Q; ++ i) { q[i].l = read(); q[i].r = read(); q[i].id = i; } sort(q + 1, q + Q + 1); Segment_Tree_Beat::build(1, 1, n); int R = 1; for (int i = 1; i <= Q; ++ i) { while (R < q[i].r) modify(++ R); ans[q[i].id] = Segment_Tree_Beat::query(1, q[i].l); } for (int i = 1; i <= Q; ++ i) printf("%d\n", ans[i]); return 0; }