P3215 括號修復 題解

Laijinyi發表於2024-10-07

Statement

維護一個括號序列,有以下操作:

  • 區間覆蓋
  • 區間翻轉
  • 區間反轉(左括號變右括號,右括號變左括號)
  • 區間問最少改多少位能使括號序列合法,保證有解

Solution

單純沒想到答案怎麼算。。。

首先一段括號序,如果消除中間的所有匹配,最終一定形如 ))))(((,這個資訊是可合併的

設這時左括號數為 \(a\),右括號數為 \(b\),答案等於 \(\lceil\frac a2\rceil+\lceil\frac b2\rceil\)

對於區間翻轉和區間反轉,再維護一下翻轉、反轉後的 \(a\)\(b\) 即可。

套上 FHQ 做完了。

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 1e5 + 10;
struct Item {
	int x, y;
	Item operator+ (const Item& rhs) const {
		return (Item){x + max(0, rhs.x - y), rhs.y + max(0, y - rhs.x)};
	}
} a[N], ai[N], as[N], asi[N], V[N], Vi[N];
int n, q, tot, rt, A, B, C, b[N], sz[N], co[N], sw[N], in[N], ch[N][2];
mt19937 rnd(251);
string s;

int New(char c) {
	sz[++tot] = 1, b[tot] = rnd(), co[tot] = 2;
	V[tot].x = Vi[tot].y = a[tot].x = ai[tot].y = as[tot].x = asi[tot].y = c == ')';
	V[tot].y = Vi[tot].x = a[tot].y = ai[tot].x = as[tot].y = asi[tot].x = !a[tot].x;
	return tot;
}
void up(int u) {
	sz[u] = sz[ch[u][0]] + 1 + sz[ch[u][1]];
	a[u] = a[ch[u][0]] + V[u] + a[ch[u][1]];
	ai[u] = ai[ch[u][0]] + Vi[u] + ai[ch[u][1]];
	as[u] = as[ch[u][1]] + V[u] + as[ch[u][0]];
	asi[u] = asi[ch[u][1]] + Vi[u] + asi[ch[u][0]];
}
void Cov(int u, int o) {
	co[u] = o, in[u] = 0;
	if (o) V[u].x = Vi[u].y = 1, a[u].x = ai[u].y = as[u].x = asi[u].y = sz[u], V[u].y = Vi[u].x = a[u].y = ai[u].x = as[u].y = asi[u].x = 0;
	else V[u].y = Vi[u].x = 1, a[u].y = ai[u].x = as[u].y = asi[u].x = sz[u], V[u].x = Vi[u].y = a[u].x = ai[u].y = as[u].x = asi[u].y = 0;
}
void Swp(int u) {
	swap(a[u], as[u]), swap(ai[u], asi[u]), swap(ch[u][0], ch[u][1]), sw[u] ^= 1;
}
void Inv(int u) {
	swap(a[u], ai[u]), swap(as[u], asi[u]), swap(V[u], Vi[u]), in[u] ^= 1;
}
void down(int u) {
	if (co[u] != 2) Cov(ch[u][0], co[u]), Cov(ch[u][1], co[u]), co[u] = 2;
	if (sw[u]) Swp(ch[u][0]), Swp(ch[u][1]), sw[u] = 0;
	if (in[u]) Inv(ch[u][0]), Inv(ch[u][1]), in[u] = 0;
}
void spl(int u, int k, int &x, int &y) {
	if (!u) return (void)(x = y = 0);
	down(u);
	if (k <= sz[ch[u][0]]) y = u, spl(ch[u][0], k, x, ch[u][0]);
	else x = u, spl(ch[u][1], k - sz[ch[u][0]] - 1, ch[u][1], y);
	up(u);
}
int mer(int u, int v) {
	if (!u || !v) return u | v;
	down(u), down(v);
	if (b[u] < b[v]) return ch[u][1] = mer(ch[u][1], v), up(u), u;
	else return ch[v][0] = mer(u, ch[v][0]), up(v), v;
}

int F(int x) {
	return x / 2 + (x % 2 == 1);
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> n >> q >> s;
	rep(i, 0, n - 1) rt = mer(rt, New(s[i]));
	while (q--) {
		string op;
		int l, r;
		char c;
		cin >> op >> l >> r;
		spl(rt, l - 1, A, B), spl(B, r - l + 1, B, C);
		if (op[0] == 'R') cin >> c, Cov(B, c == ')');
		if (op[0] == 'S') Swp(B);
		if (op[0] == 'I') Inv(B);
		if (op[0] == 'Q') cout << F(a[B].x) + F(a[B].y) << '\n';
		rt = mer(mer(A, B), C);
	}
	return 0;
}

相關文章