题解:CF1678B2 Tokitsukaze and Good 01-String (hard version)
提供一种线段树做法。
设
对于
而我们发现将
那么无脑维护线段树即可,就是维护区间
#include <bits/stdc++.h>
using namespace std;
int T;
int n;
char s[200010];
struct Node {
int maxn, d;
int add;
};
struct SGT {
Node tr[800010];
void pushup(int u) {
tr[u].maxn = min(tr[u << 1].maxn, tr[u << 1 | 1].maxn);
if (tr[u << 1].maxn < tr[u << 1 | 1].maxn) tr[u].d = tr[u << 1].d;
else if (tr[u << 1].maxn > tr[u << 1 | 1].maxn) tr[u].d = tr[u << 1 | 1].d;
else tr[u].d = min(tr[u << 1].d, tr[u << 1 | 1].d);
}
void pushdown(int u) {
tr[u << 1].maxn += tr[u].add;
tr[u << 1 | 1].maxn += tr[u].add;
tr[u << 1].add += tr[u].add;
tr[u << 1 | 1].add += tr[u].add;
}
void modify(int u, int l, int r, int x, Node d) {
if (l == r) {
tr[u] = d;
return;
}
pushdown(u);
int mid = (l + r) >> 1;
if (x <= mid) modify(u << 1, l, mid, x, d);
else modify(u << 1 | 1, mid + 1, r, x, d);
pushup(u);
}
void modify(int u, int l, int r, int ql, int qr, int d) {
if (l >= ql && r <= qr) {
tr[u].add += d;
tr[u].maxn += d;
return;
}
pushdown(u);
int mid = (l + r) >> 1;
if (ql <= mid) modify(u << 1, l, mid, ql, qr, d);
if (qr > mid) modify(u << 1 | 1, mid + 1, r, ql, qr, d);
pushup(u);
}
Node query(int u, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return tr[u];
pushdown(u);
int mid = (l + r) >> 1;
Node res = {0, 0, 0};
bool is_l = false;
if (ql <= mid) res = query(u << 1, l, mid, ql, qr), is_l = true;
if (qr > mid) {
if (!is_l) res = query(u << 1 | 1, mid + 1, r, ql, qr);
else {
auto t = query(u << 1 | 1, mid + 1, r, ql, qr);
if (t.maxn == res.maxn) res.d = min(res.d, t.d);
if (t.maxn < res.maxn) res = t;
}
}
return res;
}
} Tr[2];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
scanf("%s", s + 1);
Node res = {0, 1000000000};
for (int i = 1; i <= n; ++i) {
if (s[i] == '0') Tr[1].modify(1, 0, (n + 1) / 2, 0, (i + 1) / 2 - 1, 1);
else Tr[0].modify(1, 0, (n + 1) / 2, 0, (i + 1) / 2 - 1, 1);
if (!(i & 1)) {
auto a1 = Tr[1].query(1, 0, (n + 1) / 2, 0, i / 2 - 1), a2 = Tr[0].query(1, 0, (n + 1) / 2, 0, i / 2 - 1);
a1.d++, a2.d++;
a1.add = a2.add = 0;
// cout << a1.maxn << ' ' << a1.d << ' ' << a2.maxn << ' ' << a2.d << endl;
if (i == n) {
res.maxn = min(a1.maxn, a2.maxn);
if (a1.maxn == res.maxn) res.d = a1.d;
if (a2.maxn == res.maxn) res.d = min(res.d, a2.d);
}
Tr[1].modify(1, 0, (n + 1) / 2, i / 2, a2);
Tr[0].modify(1, 0, (n + 1) / 2, i / 2, a1);
}
}
printf("%d %d\n", res.maxn, res.d);
for (int i = 0; i <= n * 3 + 10; ++i) Tr[0].tr[i] = Tr[1].tr[i] = {0, 0, 0};
}
return 0;
}