Dyd's Blog

He who has a strong enough why can bear almost any how.

luoguP6627 [省选联考 2020 B 卷] 幸运数字

线段树,难点在转化题意和离散化确定答案上

幸运数字

思路

首先把 $2, 3$ 都转化为 $1$ 一样的区间操作,就是化为区间 $[A, A]$ 和 $(-\infty, B] \cup [B, +\infty)$

不难想到离散化后在值域线段树上区间修改,但问题是答案的可能值,因为“如果有多个幸运数字能够得到最大优惠额度,输出绝对值最小的那个。如果还有多个,则输出值最大的”太 shit 了

仔细思考不难发现,答案只有可能在 $L, R, L - 1, R + 1, A - 1, A, A + 1, B - 1, B, B + 1, +\infty, -\infty, 0$ 中出现,所以干脆就都甩进去离散化即可

代码

注意线段树的空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <bits/stdc++.h>
#define eb emplace_back
const int N = 1e5 + 100, inf = 0x3f3f3f3f;
int n, nn, tot, as1 = 0, as2 = 0;
struct LT
{
#define lc (u << 1)
#define rc ((u << 1) | 1)
#define mid ((l + r) >> 1)
int tg[N * 24], v[N * 24];
void dw(int u)
{
if (tg[u])
{
tg[lc] ^= tg[u], v[lc] ^= tg[u];
tg[rc] ^= tg[u], v[rc] ^= tg[u];
tg[u] = 0;
}
}
void mdf(int ql, int qr, int d, int u = 1, int l = 1, int r = nn)
{
if (ql <= l && r <= qr) return tg[u] ^= d, void(v[u] ^= d);
dw(u);
if (ql <= mid) mdf(ql, qr, d, lc, l, mid);
if (qr > mid) mdf(ql, qr, d, rc, mid + 1, r);
}
int ask(int pos, int u = 1, int l = 1, int r = nn)
{
if (l == r) return v[u];
dw(u);
return pos <= mid ? ask(pos, lc, l, mid) : ask(pos, rc, mid + 1, r);
}
#undef lc
#undef rc
#undef mid
} lt;
std::array<int, 3> q[N * 3];
std::vector<int> xx;
int lb(int x){ return std::lower_bound(xx.begin(), xx.end(), x) - xx.begin() + 1; }
int main()
{
scanf("%d", &n);
xx.eb(0);
for (int i = 1, t, l, r, w; i <= n; ++i)
{
scanf("%d %d %d", &t, &l, &r);
if (t == 1)
{
scanf("%d", &w);
q[++tot] = {l, r, w};
xx.eb(l), xx.eb(r), xx.eb(l - 1), xx.eb(r + 1);
}
else if (t == 2) q[++tot] = {l, l, r}, xx.eb(l), xx.eb(l - 1), xx.eb(l + 1);
else q[++tot] = {-inf, l - 1, r}, q[++tot] = {l + 1, inf, r}, xx.eb(l), xx.eb(l - 1), xx.eb(l + 1);
}
std::sort(xx.begin(), xx.end());
xx.erase(std::unique(xx.begin(), xx.end()), xx.end());
nn = xx.size();
for (int i = 1; i <= tot; ++i) lt.mdf(lb(q[i][0]), lb(q[i][1]), q[i][2]);
for (int i = xx.size(), t; i; --i)
{
t = lt.ask(i);
if (t > as1) as1 = t, as2 = xx[i - 1];
else if (t == as1 && std::abs(xx[i - 1]) < std::abs(as2)) as2 = xx[i - 1];
}
printf("%d %d\n", as1, as2);
return 0;
}