QOJ5302/GYM104090B Useful Algorithm 题解(线段树维护 (max, +) 卷积)
考虑交换求值顺序,先枚举进位的位置 \(x\),然后找到两个在这个位置进位的数 \(c_i,c_j\)。两个数相加 \(c_i+c_j\) 在第 \(x\) 位进位当且仅当 \(c_i \bmod 2^x + c_j\bmod 2^x \ge 2^x\)。
于是我们设 \(f_A\) 表示在所有 \(c_i \bmod 2^x = A\) 的 \(i\) 中 \(d_i\) 的最大值,即 \(f_A = \max_{c_i \bmod 2^x = A}d_i\)。要求的答案即为 \(\max_{x=1}^m \max_{c_i + c_j \ge 2^x} f_i+f_j\),令 \(g_i=2^x-f_i\),式子转换为 \(\max_{i\le j} g_i+f_j\)。
像这种结构的 \((\max, +)\) 卷积可以用线段树维护:每个节点维护当前节点内的 \(\max f_i, \max g_i, \max_{i\le j} g_i+f_j\),在 pushup 的时候考虑做儿子的 \(\max g\) 和右儿子的 \(\max f\) 相加是否更优即可。
最终时间复杂度 \(O(nm \log n)\)。
const int MAXN = 1e5 + 5;
int n, m, q, c[MAXN], d[MAXN], w[20], rt[20], tot;
unordered_map<int, multiset<int>> f[20], g[20];
struct _node {
int sm, f, g, ls, rs;
} tr[4000005];
#define lson tr[p].ls
#define rson tr[p].rs
struct _sgt {
void pushup(int p) {
tr[p].sm = max({tr[lson].sm, tr[rson].sm, tr[lson].g + tr[rson].f});
tr[p].f = max(tr[lson].f, tr[rson].f);
tr[p].g = max(tr[lson].g, tr[rson].g);
}
void modifyf(int &p, int l, int r, int k, int v) {
if (!p) {
p = ++tot;
tr[p].sm = tr[p].f = tr[p].g = INT_MIN;
}
if (l == r) {
tr[p].f = v;
tr[p].sm = tr[p].f + tr[p].g;
return;
}
if (k <= mid) modifyf(lson, l, mid, k, v);
else modifyf(rson, mid + 1, r, k, v);
pushup(p);
}
void modifyg(int &p, int l, int r, int k, int v) {
if (!p) {
p = ++tot;
tr[p].sm = tr[p].f = tr[p].g = INT_MIN;
}
if (l == r) {
tr[p].g = v; tr[p].sm = tr[p].f + tr[p].g;
return;
}
if (k <= mid) modifyg(lson, l, mid, k, v);
else modifyg(rson, mid + 1, r, k, v);
pushup(p);
}
#undef lson
#undef rson
} t[18];
int query() {
int ans = 0;
for (int x = 1; x <= m; ++x) {
ans = max(ans, tr[rt[x]].sm * w[x]);
}
return ans;
}
void work() {
cin >> n >> m >> q;
for (int i = 1; i <= m; ++i)
cin >> w[i];
for (int i = 1; i <= n; ++i)
cin >> c[i];
for (int i = 1; i <= n; ++i)
cin >> d[i];
tr[0] = {INT_MIN, INT_MIN, INT_MIN};
for (int x = 1; x <= m; ++x) {
int S = (1ll << x) - 1;
for (int i = 1; i <= n; ++i) {
f[x][c[i] & S].insert(d[i]);
g[x][S + 1 - (c[i] & S)].insert(d[i]);
}
for (auto [i, st]:f[x]) {
t[x].modifyf(rt[x], 0, 1ll << x, i, *st.rbegin());
}
for (auto [i, st]:g[x]) {
t[x].modifyg(rt[x], 0, 1ll << x, i, *st.rbegin());
}
}
int lst = 0;
cout << (lst = query()) << endl;
while (q--) {
int x, u, v; cin >> x >> u >> v;
x = x ^ lst; u = u ^ lst; v = v ^ lst;
for (int i = 1; i <= m; ++i) {
int S = (1ll << i) - 1;
auto &fix = f[i][c[x] & S], &gix = g[i][S + 1 - (c[x] & S)];
fix.erase(fix.find(d[x]));
if (fix.size()) t[i].modifyf(rt[i], 0, 1ll << i, c[x] & S, *fix.rbegin());
else t[x].modifyf(rt[i], 0, 1ll << i, c[x] & S, INT_MIN);
gix.erase(gix.find(d[x]));
if (gix.size()) t[i].modifyg(rt[i], 0, 1ll << i, S + 1 - (c[x] & S), *gix.rbegin());
else t[x].modifyg(rt[i], 0, 1ll << i, S + 1 - (c[x] & S), INT_MIN);
}
for (int i = 1; i <= m; ++i) {
int S = (1ll << i) - 1;
auto &fix = f[i][u & S], &gix = g[i][S + 1 - (u & S)];
fix.insert(v); gix.insert(v);
t[i].modifyf(rt[i], 0, 1ll << i, u & S, *fix.rbegin());
t[i].modifyg(rt[i], 0, 1ll << i, S + 1 - (u & S), *gix.rbegin());
}
c[x] = u;
d[x] = v;
cout << (lst = query()) << endl;
}
}

浙公网安备 33010602011771号