2018-2019 ACM-ICPC, Asia Shenyang Regional Contest E The Kouga Ninja Scrolls

题目描述

http://codeforces.com/gym/101955/problem/E

Solution

我们考虑用线段树维护,注意到修改都是单点修改,所以我们只需要考虑合并

注意到曼哈顿距离可以通过维护 $2^k$ 个变量来将绝对值拆开,所以本质上相当于我们只需要维护不同部落的和的最大值

我们直接维护区间不同部落的最大和次大即可

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <iostream>
#include <vector>
#include <set>
#define ll long long
#define maxn 100010
#define INF 1000000000000000000ll
using namespace std;

int n, m, c[maxn];

ll a[maxn], b[maxn];

#define lc i << 1
#define rc i << 1 | 1
struct Seg {
ll v, secmax[4], max[4], cm[4], cs[4];
} T[maxn * 4], _;
inline Seg maintain(const Seg &ls, const Seg &rs) {
Seg o; o.v = max(ls.v, rs.v);
for (int i = 0; i < 4; ++i) {
if (ls.cm[i] != rs.cm[i ^ 3]) o.v = max(o.v, ls.max[i] + rs.max[i ^ 3]);
if (ls.cm[i] != rs.cs[i ^ 3]) o.v = max(o.v, ls.max[i] + rs.secmax[i ^ 3]);
if (ls.cs[i] != rs.cm[i ^ 3]) o.v = max(o.v, ls.secmax[i] + rs.max[i ^ 3]);
if (ls.cs[i] != rs.cs[i ^ 3]) o.v = max(o.v, ls.secmax[i] + rs.secmax[i ^ 3]);
if (ls.cm[i] != rs.cm[i]) {
o.max[i] = max(ls.max[i], rs.max[i]);
o.cm[i] = ls.max[i] >= rs.max[i] ? ls.cm[i] : rs.cm[i];
if (min(ls.max[i], rs.max[i]) >= max(ls.secmax[i], rs.secmax[i])) {
o.secmax[i] = min(ls.max[i], rs.max[i]);
o.cs[i] = ls.max[i] < rs.max[i] ? ls.cm[i] : rs.cm[i];
}
else {
if (ls.secmax[i] >= rs.secmax[i]) {
o.secmax[i] = ls.secmax[i];
o.cs[i] = ls.cs[i];
}
else {
if (rs.cs[i] != o.cm[i]) {
o.secmax[i] = rs.secmax[i];
o.cs[i] = rs.cs[i];
}
else {
o.secmax[i] = -INF;
o.cs[i] = 0;
}
}
}
}
else {
o.max[i] = max(ls.max[i], rs.max[i]);
o.cm[i] = ls.max[i] >= rs.max[i] ? ls.cm[i] : rs.cm[i];
o.secmax[i] = max(ls.secmax[i], rs.secmax[i]);
o.cs[i] = ls.secmax[i] >= rs.secmax[i] ? ls.cs[i] : rs.cs[i];
}
}
return o;
}

void build(int i, int l, int r) {
if (l == r) {
T[i].max[0] = a[l] + b[l];
T[i].max[1] = a[l] - b[l];
T[i].max[2] = -a[l] + b[l];
T[i].max[3] = -a[l] - b[l];
for (int o = 0; o < 4; ++o) T[i].cm[o] = c[l], T[i].cs[o] = 0, T[i].secmax[o] = -INF;
T[i].v = 0; return ;
} int m = l + r >> 1;
build(lc, l, m); build(rc, m + 1, r);
T[i] = maintain(T[lc], T[rc]);
}

void update(int i, int l, int r, int k, ll x, ll y) {
if (l == r) {
T[i].max[0] = x + y;
T[i].max[1] = x - y;
T[i].max[2] = -x + y;
T[i].max[3] = -x - y;
return ;
} int m = l + r >> 1;
if (k <= m) update(lc, l, m, k, x, y);
else update(rc, m + 1, r, k, x, y);
T[i] = maintain(T[lc], T[rc]);
}

void update(int i, int l, int r, int k, int c) {
if (l == r) {
for (int o = 0; o < 4; ++o) T[i].cm[o] = c;
return ;
} int m = l + r >> 1;
if (k <= m) update(lc, l, m, k, c);
else update(rc, m + 1, r, k, c);
T[i] = maintain(T[lc], T[rc]);
}

Seg query(int i, int l, int r, int L, int R) {
if (l > R || r < L) return _;
if (L <= l && r <= R) return T[i];
int m = l + r >> 1;
return maintain(query(lc, l, m, L, R), query(rc, m + 1, r, L, R));
}

inline void solve_1() {
int x, y, z; cin >> z >> x >> y;
a[z] += x; b[z] += y;
update(1, 1, n, z, a[z], b[z]);
}

inline void solve_2() {
int x, y; cin >> x >> y;
c[x] = y;
update(1, 1, n, x, c[x]);
}

inline void solve_3() {
int x, y; cin >> x >> y;
cout << query(1, 1, n, x, y).v << "\n";
}

int icase;
void work() {
cin >> n >> m; cout << "Case #" << ++icase << ":\n";
for (int i = 0; i < 4; ++i) _.max[i] = _.secmax[i] = -INF, _.cm[i] = 0, _.cs[i] = n + 1, _.v = 0;
for (int i = 1; i <= n; ++i) cin >> a[i] >> b[i] >> c[i];
build(1, 1, n);
for (int i = 1; i <= m; ++i) {
int opt; cin >> opt;
if (opt == 1) solve_1();
else if (opt == 2) solve_2();
else solve_3();
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T;
while (T--) work();
return 0;
}