CF793F Julia the snail 题解
一、题目:
二、思路:
这道题的官方题解是分块,在这里提供一种吉司机线段树的做法。
设所有的传送门为二元组 \((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;
}