AT_abc223_f [ABC223F] Parenthesis Checking 题解

题目传送门

思路

首先,括号串匹配当切仅当左括号和右括号数量相等,且任意子串 \([1,x]\)\(1\le x\le |S|\))左括号数量减右括号数量都 \(\ge 0\)

令左括号贡献值为 \(1\),右括号贡献值为 \(-1\)\(sum_i\) 代表子串 \([1,i]\) 贡献的和。

那对于任意子串,其为合法括号匹配串的充分必要条件为:

  1. 串内左括号和右括号数量相等,即 \(sum_r = sum_{l-1}\)
  2. 对于任意 \(i\)\(l \le i \le r\)),都有 \(sum_i \ge 0\),即 $$\begin{aligned} \min _ {l \le i \le r}sum_i \ge 0\end{aligned}$$。

那我们就可以用线段树维护贡献前缀和的最小值。对于第一个性质,每次单点查询 \(2\) 次,然后看是否相等。对于第 \(2\) 个性质,区间查询 \([l, r]\) 的最小值。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 5;

int n, q;
int t[N];
char s[N];

struct seg_tree
{
	struct node
	{
		int l, r, minn, lazy;
	} tr[4 * N];
	void push_up(int p)
	{
		tr[p].minn = min(tr[p * 2].minn, tr[p * 2 + 1].minn);
	}
	void push_down(int p)
	{
		if (tr[p].lazy)
		{
			tr[p * 2].lazy += tr[p].lazy;
			tr[p * 2 + 1].lazy += tr[p].lazy;
			tr[p * 2].minn += tr[p].lazy;
			tr[p * 2 + 1].minn += tr[p].lazy;
			tr[p].lazy = 0;
		}
	}
	void build(int p, int l, int r)
	{
		tr[p] = {l, r, (int)(2e9), 0};
		if (l == r)
		{
			tr[p].minn = t[l];
			return;
		}
		int mid = (l + r) >> 1;
		build(p * 2, l, mid);
		build(p * 2 + 1, mid + 1, r);
		push_up(p);
	}
	void update(int p, int l, int r, int x)
	{
		if (tr[p].r < l || tr[p].l > r) return; 
		if (tr[p].l >= l && tr[p].r <= r)
		{
			tr[p].minn += x;
			tr[p].lazy += x;
			return;
		}
		push_down(p);
		int mid = (l + r) >> 1;
		if (l <= mid) update(p * 2, l, r, x);
		if (r > mid) update(p * 2 + 1, l, r, x);
		push_up(p);
	}
	int query(int p, int l, int r)
	{
		if (tr[p].r < l || tr[p].l > r) return (int)(2e9); 
		if (tr[p].l >= l && tr[p].r <= r) return tr[p].minn;
		push_down(p);
		int mid = (tr[p].l + tr[p].r) >> 1, res = (int)(2e9);
		if (l <= mid) res = min(res, query(p * 2, l, r));
		if (r > mid) res = min(res, query(p * 2 + 1, l, r));
		return res;
	}
} ST;

signed main()
{
	scanf("%lld%lld%s", &n, &q, s + 1);
	for (int i = 1; i <= n; i++)
	{
		if (s[i] == '(') t[i] = t[i - 1] + 1;
		else t[i] = t[i - 1] - 1;
	}
	ST.build(1, 1, n);
	while (q--)
	{
		int op, l, r;
		scanf("%lld%lld%lld", &op, &l, &r);
		if (op == 1)
		{
			if (s[l] == s[r]) continue;
			if (s[l] == '(')
			{
				ST.update(1, l, n, -2);
				ST.update(1, r, n, 2);
			}
			else
			{
				ST.update(1, l, n, 2);
				ST.update(1, r, n, -2);
			}
			swap(s[l], s[r]);
		}
		else
		{
			int k1 = 0, k2 = ST.query(1, r, r), k3 = ST.query(1, l, r);
			if (l == 1) k1 = 0;
			else k1 = ST.query(1, l - 1, l - 1);
			if (k1 == k2 && k3 >= k1) puts("Yes");
			else puts("No");
		}
	}
	return 0;
}
posted @ 2025-07-19 22:03  lucasincyber  阅读(10)  评论(0)    收藏  举报