20250807 做题记录
下午补题过了 没有重复颜色,写了如下题解:
首先考虑这个“没有重复颜色的区间”应该满足什么条件。
发现,处理出每一个位置的左边,上一个同色的位置,记为 \(lst[i]\)。则,右端点为 \(i\),左端点要求 \(\ge\max_{j\in[1,i]}lst[j]\),记其为 \(L\)。
考虑询问,每次询问一个区间的时候,我们查询 \([l,r]\) 的右端点的答案,并限制这些点的 \(L\) 与 \(l\) 取 \(\max\)。
容易发现 \(L\) 是单增的,考虑先把询问区间拆分为 \(\log\) 个满的区间,然后会发现 \(l\) 会覆盖当前区间的一个前缀,其后缀仍是 \(L\)。
如果这个分界线在左边,则我们希望处理好右边的答案,并递归左边。注意到,对于右边的 \(L\) 的限制,它只受当前区间的影响,具体而言,右边的答案是 \(\max_{i\in[mid+1,r]}(S_i-S_{\max_{j\in[l,i]}lst[j]})\)。因为左边已经受到 \(l\) 限制,而在当前区间内到了一个位置,\(L\) 就 \(>l\) 了,因此一定存在一个当前线段树区间内的 \(lst\) 是真正有贡献的,只需考虑当前区间内的 \(lst\) 对 \(L\) 的贡献就行了。
如果分界线在右边,则左边由于 \(S\) 也是单增的,左边的最大值是 \(S_{mid}-S_v\),递归右边,但是要给 \(l\) 加一个左边这部分的限制,即变为 \(\max(l,\max_{i\in[l,mid]}lst_i)\)。
判断分界线在左边还是右边只需要维护区间 \(\max lst\) 即可。将当前区间右区间的答案放在当前区间存储,即 pushup 的时候,使 tr[p].ans = _Query(tr[ls].Lmax, m + 1, t, rs) 即可(注意右边的答案是受当前区间左半部分的影响的(它的 \(L\) 对应的 \(lst\) 的贡献范围是当前整个区间),因此传入 tr[ls].Lmax)。
#include <bits/stdc++.h>
using namespace std;
void File(string s) { freopen((s + ".in").c_str(), "r", stdin), freopen((s + ".out").c_str(), "w", stdout); }
const int N = 200005;
int n, m, q, co[N], lst[N];
long long pre[N];
set<int> po[N];
struct Segment_tree {
#define ls (p << 1)
#define rs (p << 1 | 1)
struct Node {
long long Lmax, Lmin, ans;
Node (long long _lmax = 0, long long _lmin = 0, long long _ans = 0) { Lmax = _lmax, Lmin = _lmin, ans = _ans; }
} tr[N << 2];
void Pushup(int s, int t, int p) {
tr[p].Lmax = max(tr[ls].Lmax, tr[rs].Lmax);
tr[p].Lmin = min(tr[ls].Lmin, tr[rs].Lmin);
int m = (s + t) >> 1;
tr[p].ans = _Query(tr[ls].Lmax, m + 1, t, rs);
}
void Build(int s, int t, int p) {
if (s == t) {
tr[p] = { lst[s], lst[s], pre[s] - pre[lst[s]] };
return ;
}
int m = (s + t) >> 1;
Build(s, m, ls);
Build(m + 1, t, rs);
Pushup(s, t, p);
}
void Modify(int x, int s, int t, int p) {
if (s == t) {
tr[p] = { lst[x], lst[x], pre[s] - pre[lst[x]] };
return ;
}
int m = (s + t) >> 1;
if (x <= m) {
Modify(x, s, m, ls);
}
else {
Modify(x, m + 1, t, rs);
}
Pushup(s, t, p);
}
long long _Query(int v, int s, int t, int p) {
if (s == t) {
return pre[s] - pre[max(lst[s], v)];
}
int m = (s + t) >> 1;
if (tr[ls].Lmax < v) {
return max(pre[m] - pre[v], _Query(v, m + 1, t, rs));
}
else {
return max(_Query(v, s, m, ls), tr[p].ans);
}
}
long long Query(int l, int r, int v, int s, int t, int p) {
if (l <= s && r >= t) {
return _Query(v, s, t, p);
}
int m = (s + t) >> 1;
long long ans = 0;
if (l <= m) {
ans = max(ans, Query(l, r, v, s, m, ls));
}
if (r > m) {
ans = max(ans, Query(l, r, max((long long)v, tr[ls].Lmax), m + 1, t, rs));
}
return ans;
}
} seg;
signed main() {
File("norepeat");
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++) {
scanf("%lld", pre + i);
pre[i] += pre[i - 1];
}
for (int i = 1; i <= m; i++) {
po[i].insert(0);
}
for (int i = 1; i <= n; i++) {
scanf("%d", co + i);
lst[i] = *po[co[i]].rbegin();
po[co[i]].insert(i);
}
seg.Build(1, n, 1);
while (q--) {
int opt;
scanf("%d", &opt);
if (opt == 1) {
int l, r;
scanf("%d%d", &l, &r);
printf("%lld\n", seg.Query(l, r, l - 1, 1, n, 1));
}
else {
int p, w;
scanf("%d%d", &p, &w);
auto it = next(po[co[p]].lower_bound(p));
po[co[p]].erase(p);
if (it != po[co[p]].end()) {
lst[*it] = *prev(it);
seg.Modify(*it, 1, n, 1);
}
it = po[w].lower_bound(p);
if (it != po[w].end()) {
lst[*it] = p;
seg.Modify(*it, 1, n, 1);
}
it = po[w].insert(p).first;
lst[p] = *prev(it);
co[p] = w;
seg.Modify(p, 1, n, 1);
}
}
return 0;
}

浙公网安备 33010602011771号