1. 程式人生 > 其它 >CF793F Julia the snail 題解

CF793F Julia the snail 題解

一、題目:

洛谷原題

codeforces原題

二、思路:

這道題的官方題解是分塊,在這裡提供一種吉司機線段樹的做法。

設所有的傳送門為二元組 \((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;
}