CF1609 E. William The Oblivious
题意
给定一个长度为
n
n
n的字符串
s
s
s,字符串内只含有
a
,
b
,
c
a,b,c
a,b,c三种字符,即
∀
i
,
s
[
i
]
\forall i,s[i]
∀i,s[i]为
a
,
b
,
c
a,b,c
a,b,c中一个。
有
q
q
q次询问,每次询问会将
s
[
p
o
s
]
s[pos]
s[pos]修改成
v
v
v,即
s
[
p
o
s
]
=
v
s[pos]=v
s[pos]=v。
你可以进行一种操作,使得任意一个位置的 s [ i ] s[i] s[i]转变成 a , b , c a,b,c a,b,c中的一个字符。
对于每次询问,需要回答:将当前字符串修改成子序列中不含abc的最小操作次数。
思路
用线段树维护每一个连续子区间的信息,定义状态为:
- d p [ r o o t ] [ 0 ] dp[root][0] dp[root][0]:将当前子串修改成子序列中不含a的最小操作次数。
- d p [ r o o t ] [ 1 ] dp[root][1] dp[root][1]:将当前子串修改成子序列中不含b的最小操作次数。
- d p [ r o o t ] [ 2 ] dp[root][2] dp[root][2]:将当前子串修改成子序列中不含c的最小操作次数。
- d p [ r o o t ] [ 3 ] dp[root][3] dp[root][3]:将当前子串修改成子序列中不含ab的最小操作次数。
- d p [ r o o t ] [ 4 ] dp[root][4] dp[root][4]:将当前子串修改成子序列中不含bc的最小操作次数。
- d p [ r o o t ] [ 5 ] dp[root][5] dp[root][5]:将当前子串修改成子序列中不含abc的最小操作次数。
则状态转移为:
root.dp[0] = left.dp[0] + right.dp[0];
root.dp[1] = left.dp[1] + right.dp[1];
root.dp[2] = left.dp[2] + right.dp[2];
root.dp[3] = min(left.dp[3] + right.dp[1], left.dp[0] + right.dp[3]);
root.dp[4] = min(left.dp[1] + right.dp[4], left.dp[4] + right.dp[2]);
root.dp[5] = min(left.dp[0] + right.dp[5],
min(left.dp[5] + right.dp[2], left.dp[3] + right.dp[4]));
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, q;
char s[N];
struct Tree {
int l, r;
int dp[6];
} tr[N * 4];
void pushup(int p) {
auto &root = tr[p], &left = tr[p << 1], &right = tr[p << 1 | 1];
root.dp[0] = left.dp[0] + right.dp[0];
root.dp[1] = left.dp[1] + right.dp[1];
root.dp[2] = left.dp[2] + right.dp[2];
root.dp[3] = min(left.dp[3] + right.dp[1], left.dp[0] + right.dp[3]);
root.dp[4] = min(left.dp[1] + right.dp[4], left.dp[4] + right.dp[2]);
root.dp[5] = min(left.dp[0] + right.dp[5],
min(left.dp[5] + right.dp[2], left.dp[3] + right.dp[4]));
}
void build(int p, int l, int r) {
tr[p] = {l, r};
if (l == r) {
memset(tr[p].dp, 0, sizeof tr[p].dp);
tr[p].dp[s[l] - 'a'] = 1;
return;
}
int mid = (tr[p].l + tr[p].r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
pushup(p);
}
void modify(int p, int x, char v) {
if (tr[p].l == tr[p].r && tr[p].l == x) {
s[x] = v;
memset(tr[p].dp, 0, sizeof tr[p].dp);
tr[p].dp[s[x] - 'a'] = 1;
return;
}
int mid = (tr[p].l + tr[p].r) >> 1;
if (x <= mid)
modify(p << 1, x, v);
else
modify(p << 1 | 1, x, v);
pushup(p);
}
int main() {
cin >> n >> q;
cin >> s + 1;
build(1, 1, n);
while (q--) {
int x, res = inf;
char val;
cin >> x >> val;
modify(1, x, val);
cout << tr[1].dp[5] << "\n";
}
return 0;
}