F - Parenthesis Checking
思维+线段树
题意:
老套的合法括号序列
两个操作
1
l
r
1 \ l \ r
1 l r 表示交换两个位置
2
l
r
2 \ l \ r
2 l r 表示询问这个区间的括号序列是否合法
思路:
考虑把
(
(
( 看作 1,
)
)
) 看作
−
1
-1
−1
显然一个合法的括号序列区间和应该是
0
0
0,但这一个约束条件显然不够,
还需要约束区间内的序列也是合法序列,不停的递归的这种。
主要是该如何查询这个区间是否合法
一个巧妙的思路是对序列求一个前缀和
然后用线段树维护区间最小值
首先查询
t
r
[
l
−
1
]
tr[l-1]
tr[l−1] 和
t
r
[
r
]
tr[r]
tr[r] 的值,如果这两个值相等说明区间
l
,
r
l,r
l,r 的括号区间正好一半
(
(
(,一半
)
)
)。
这个比较好理解,而区间最小值大于等于
t
r
[
l
−
1
]
tr[l-1]
tr[l−1] 就可以说明,所有的
)
)
),都可以在左边找到一个
(
(
(。
满足这两个条件的就是合法的
code:
#include<bits/stdc++.h>
#define ls (p << 1)
#define rs (p << 1 | 1)
#define endl '\n';
#define ll long long
using namespace std;
const int maxn = 2e5 + 9;
const int inf = 0x3f3f3f3f;
ll n, m;
ll tr[maxn << 2], mark[maxn << 2], a[maxn];
string s;
inline void pushup(int p)
{
tr[p] = min(tr[ls], tr[rs]);
}
inline void pushdown(int p)
{
if(!mark[p]) return;
tr[ls] += mark[p];
tr[rs] += mark[p];
mark[ls] += mark[p];
mark[rs] += mark[p];
mark[p] = 0;
}
void build(int p = 1, int cl = 1, int cr = n)
{
if(cl == cr){
tr[p] = a[cl];return;
}
int mid = (cl + cr) >> 1;
build(ls, cl, mid);
build(rs, mid + 1, cr);
pushup(p);
}
void update(int l, int r, int d, int p = 1, int cl = 1, int cr = n)
{
if(cl >= l && cr <= r){
tr[p] += d;
mark[p] += d;return;
}
pushdown(p);
int mid = (cl + cr) >> 1;
if(mid >= l) update(l, r, d, ls, cl, mid);
if(mid < r) update(l, r, d, rs, mid + 1, cr);
pushup(p);
}
int qry(int l, int r, int p = 1, int cl = 1, int cr = n)
{
if(cl > r || cr < l) return 0;
if(cl >= l && cr <= r) return tr[p];
int mid = (cl + cr) >> 1;
pushdown(p);
int ans = inf;
if(mid >= l) ans = min(ans, qry(l, r, ls, cl, mid));
if(mid < r) ans = min(ans, qry(l, r, rs, mid + 1, cr));
return ans;
}
void work()
{
cin >> n >> m;
cin >> s;
s = "@" + s;
for(int i = 1; i <= n; ++i)
a[i] = a[i-1] + (s[i] == '(' ? 1 : -1);
build();
while(m--)
{
int op, l, r;cin >> op >> l >> r;
if(op == 1){
update(l, n, s[l] == '(' ? -1 : 1);
update(r, n, s[r] == '(' ? -1 : 1);
swap(s[l], s[r]);
update(l, n, s[l] == '(' ? 1 : -1);
update(r, n, s[r] == '(' ? 1 : -1);
}
else{
int q1 = qry(l, r);
int q2 = qry(l-1, l-1);
int q3 = qry(r, r);
if(q2 == q3 && q1 >= q2) cout << "Yes\n";
else cout << "No\n";
}
}
}
int main()
{
ios::sync_with_stdio(0);
work();
return 0;
}