题意
传送门 Codeforces gym103119J Jewel Grab
题解
维护位置 i i i 相同颜色的前一个位置 p r e [ i ] pre[i] pre[i],每次查询从当前起点 l l l 出发,可走到的区间 [ l , r ) [l,r) [l,r) 满足 p r e [ i ] < s , i ∈ [ l , r ) pre[i]<s,i\in [l,r) pre[i]<s,i∈[l,r);此时 r r r 对应的颜色出现了多次(可走到这样的 r r r 至多 k + 1 k+1 k+1 个),需要维护价值的最大值,然后再从 r + 1 r+1 r+1 出发拓展。
对于满足上述条件的 r r r 可以用线段树加速,具体而言,先在树上找到满足大于等于 l l l 的位置,然后从左向右不断拓展。
总时间复杂度 O ( m k log n ) O(mk\log n) O(mklogn)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int MAXN = 2E5 + 5, SZ = 1 << 19;
int N, M, C[MAXN], V[MAXN];
int lst[MAXN], pre[MAXN];
set<int> pos[MAXN];
struct SG
{
int mx[SZ];
ll sum[SZ];
void init(int k = 0, int l = 0, int r = N)
{
if (r - l == 1)
{
mx[k] = pre[l], sum[k] = V[l];
return;
}
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
init(chl, l, m), init(chr, m, r);
mx[k] = max(mx[chl], mx[chr]);
sum[k] = sum[chl] + sum[chr];
}
void change(int a, int b, int k = 0, int l = 0, int r = N)
{
if (r <= a || b <= l)
return;
if (a <= l && r <= b)
{
mx[k] = pre[l], sum[k] = V[l];
return;
}
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
change(a, b, chl, l, m), change(a, b, chr, m, r);
mx[k] = max(mx[chl], mx[chr]);
sum[k] = sum[chl] + sum[chr];
}
ll ask_sum(int a, int b, int k = 0, int l = 0, int r = N)
{
if (r <= a || b <= l)
return 0;
if (a <= l && r <= b)
return sum[k];
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
return ask_sum(a, b, chl, l, m) + ask_sum(a, b, chr, m, r);
}
int ask_pos(int a, int b, int x, int k = 0, int l = 0, int r = N)
{
if (a <= l && mx[k] < x)
return r;
if (r - l == 1)
return l;
int m = (l + r) / 2, chl = k * 2 + 1, chr = k * 2 + 2;
if (m <= a)
return ask_pos(a, b, x, chr, m, r);
int j = ask_pos(a, b, x, chl, l, m);
if (j == m)
j = ask_pos(a, b, x, chr, m, r);
return j;
}
} tr;
void _max(int &x, int y) { x = max(x, y); }
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> M;
for (int i = 0; i < N; ++i)
cin >> C[i] >> V[i];
memset(lst, -1, sizeof(lst));
for (int i = 0; i < N; ++i)
{
pos[C[i]].insert(i);
pre[i] = lst[C[i]];
lst[C[i]] = i;
}
tr.init();
while (M--)
{
int op;
cin >> op;
if (op == 1)
{
int x, c, v;
cin >> x >> c >> v;
--x;
auto it = pos[C[x]].lower_bound(x);
auto it2 = it;
++it2;
if (it2 != pos[C[x]].end())
{
int y = *it2;
if (it == pos[C[x]].begin())
pre[y] = -1;
else
pre[y] = *(--it);
tr.change(y, y + 1);
}
pos[C[x]].erase(x);
C[x] = c, V[x] = v;
pos[C[x]].insert(x);
it = pos[C[x]].lower_bound(x);
it2 = it, ++it2;
if (it2 != pos[C[x]].end())
{
int y = *it2;
pre[y] = x;
tr.change(y, y + 1);
}
pre[x] = it == pos[C[x]].begin() ? -1 : *(--it);
tr.change(x, x + 1);
}
else
{
int s, k;
cin >> s >> k;
--s;
ll sum = 0;
map<int, int> mp;
for (int l = s; l < N;)
{
int j = tr.ask_pos(l, N, s);
sum += tr.ask_sum(l, j);
if (k == 0 || j == N)
break;
int c = C[j], v = V[j];
if (!mp.count(c))
{
sum -= V[pre[j]];
_max(mp[c], V[pre[j]]);
}
_max(mp[c], v);
--k;
l = j + 1;
}
for (auto &p : mp)
sum += p.second;
cout << sum << '\n';
}
}
return 0;
}