题目链接:https://codeforces.com/gym/103119/problem/J
看到 \(k\) 只有 \(10\),所以可以暴力跳段统计答案
维护每个位置前一个相同颜色出现的位置 \(pre[i]\),如果 \(pre[i] < s\),则说明该颜色没有在 \(s\) 之后出现过,在线段树上二分找到第一个 \(pre[x] > s\) 的 \(x\) 即可
\(pre\) 的修改要用 \(set\) 维护一下每个颜色都在哪些位置出现过,修改的时候细心一些,注意不要漏掉 \(set, la(某个颜色最后出现的位置)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200010;
const int INF = 1000000007;
int n, m;
ll v[maxn], mvc[maxn];
int c[maxn], pre[maxn], nxt[maxn], la[maxn];
set<int> cp[maxn];
struct Node{
int mx;
ll sum;
}t[maxn<<2];
void pushup(int i){
t[i].mx = max(t[i<<1].mx, t[i<<1|1].mx);
t[i].sum = t[i<<1].sum + t[i<<1|1].sum;
}
void build(int i, int l, int r){
if(l == r){
t[i].mx = pre[l];
t[i].sum = v[l];
return;
}
int mid = (l + r) >> 1;
build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r);
pushup(i);
}
void modify(int i, int p, int l, int r){
if(l == r){
t[i].mx = pre[l];
t[i].sum = v[l];
return;
}
int mid = (l + r) >> 1;
if(p <= mid) modify(i<<1, p, l, mid);
else modify(i<<1|1, p, mid + 1, r);
pushup(i);
}
ll query(int i, int l, int r, int x, int y){
if(x <= l && r <= y){
return t[i].sum;
}
int mid = (l + r) >> 1;
ll res = 0;
if(x <= mid) res += query(i<<1, l, mid, x, y);
if(y > mid) res += query(i<<1|1, mid + 1, r, x, y);
return res;
}
int find(int i, int s, int l, int r, int p){
if(l == r){
return l;
}
int mid = (l + r) >> 1;
int pos = -1;
if(t[i<<1].mx >= s && p <= mid) pos = find(i<<1, s, l, mid, p);
if(pos != -1) return pos;
if(t[i<<1|1].mx >= s) pos = find(i<<1|1, s, mid+1, r, p);
return pos;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read(), m = read();
memset(la, -1, sizeof(la));
for(int i = 1 ; i <= n ; ++i){
c[i] = read(), v[i] = read();
cp[c[i]].insert(i);
pre[i] = la[c[i]];
la[c[i]] = i;
}
memset(la, -1, sizeof(la));
for(int i = n ; i >= 1 ; --i){
nxt[i] = la[c[i]];
la[c[i]] = i;
}
memset(la, -1, sizeof(la));
for(int i = 1 ; i <= n ; ++i) la[c[i]] = i;
build(1, 1, n);
int op, k, x, y;
for(int i = 1 ; i <= m ; ++i){
op = read();
if(op == 1) {
x = read(), y = read(), k = read();
cp[c[x]].erase(x);
if(la[c[x]] == x) la[c[x]] = pre[x];
v[x] = k;
c[x] = y;
if(nxt[x] != -1){
if(pre[x] != -1){
nxt[pre[x]] = nxt[x];
pre[nxt[x]] = pre[x];
modify(1, nxt[x], 1, n);
} else{
pre[nxt[x]] = -1;
modify(1, nxt[x], 1, n);
}
} else {
if(pre[x] != -1){
nxt[pre[x]] = -1;
}
}
int pos;
set<int>::iterator it;
it = cp[y].lower_bound(x);
if(it == cp[y].end()) {
nxt[x] = -1;
pre[x] = la[y];
if(pre[x] != -1) nxt[pre[x]] = x;
modify(1, x, 1, n);
}
else {
pos = *it;
if(pre[pos] != -1){
nxt[pre[pos]] = x;
pre[x] = pre[pos];
modify(1, x, 1, n);
} else{
pre[x] = -1;
modify(1, x, 1, n);
}
nxt[x] = pos;
pre[pos] = x;
modify(1, pos, 1, n);
}
cp[y].insert(x);
la[y] = max(la[y], x);
} else{
vector<int> color;
color = vector<int>();
x = read(), k = read();
int cur = x;
ll ans = 0;
for(int j = 0 ; j <= k && cur <= n ; ++j){
int pos = find(1, x, 1, n, cur);
if(pos == -1){
ans += query(1, 1, n, cur, n);
break;
}
color.push_back(c[pos]);
if(j < k) {
if(mvc[c[pos]] == 0) mvc[c[pos]] = v[pre[pos]];
if(v[pos] > mvc[c[pos]]){
ans -= mvc[c[pos]];
ans += v[pos];
mvc[c[pos]] = v[pos];
}
}
ans += query(1, 1, n, cur, pos-1);
cur = pos + 1;
}
printf("%lld\n", ans);
for(auto u : color) mvc[u] = 0;
}
}
return 0;
}