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;
}

posted @ 2021-07-02 10:11  蓝田日暖玉生烟  阅读(98)  评论(0编辑  收藏  举报