CF2210D A Simple RBS Problem

CF2210D A Simple RBS Problem

考虑建树。每个节点的儿子表示包含在这一对括号内的匹配括号对。具体来说,遍历整个括号序列,每当遇到一个左括号就把它放进栈里,每当遇到一个右括号就把栈顶的左括号弹出来,并建立一条由当前栈顶的左括号表示的节点指向这一对匹配括号表示的节点的边。

考虑操作。不难发现,就是每次选择两个没有祖先后代关系的节点,交换它们的一段连续子树。或者选择一个节点,交换它的两段不相交的连续子树。显然,经过这样的若干次操作,树中的叶子节点的数量是不会发生改变的。从根节点向下的第一个拥有超过一个子树的节点的深度也是不变的。

接下来证明只要两棵树的这两个不变量相等那么它们就是可以相互转换的。考虑把树变成一个标准的样子。假设从根节点向下的第一个拥有超过一个子树的节点为 \(u\),如果 \(u\) 的儿子个数和叶子节点个数相等,那么树就是从根连向 \(u\),然后在 \(u\) 上挂若干条树枝。如果不是这样的,考虑变成这样。对于一个有多个儿子的节点 \(v\),考虑把它的所有儿子跟 \(u\) 的某一个儿子交换。这样 \(v\) 的儿子就只有一个了,\(u\) 的儿子则会增加,直到 \(u\) 的儿子个数等于叶子节点个数。所以只要这两个不变量相等,两棵树就可以变成一样的标准型。

code

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n;
int st[N],node[N];
char s[N],t[N];
vector<int> to[N>>1];
int dfs(int u)
{
    if (to[u].size()>1||!to[u].size()) return 0;
    return dfs(to[u][0])+1;
}
inline pair<int,int> build(char *s)
{
    for (int i=1;i<=n/2+1;++i) to[i].clear();
    int tt=0,cur=0;
    st[++tt]=0;
    node[0]=++cur;
    for (int i=1;i<=n;++i)
    {
        if (s[i]=='(')
        {
            st[++tt]=i;
            node[i]=++cur;
        }
        else
        {
            to[node[st[tt-1]]].push_back(node[st[tt]]);
            --tt;
        }
    }
    int cntl=0;
    for (int i=1;i<=cur;++i) if (!to[i].size()) ++cntl;
    return {cntl,dfs(1)};
}
inline void solve()
{
    cin>>n;
    for (int i=1;i<=n;++i) cin>>s[i];
    for (int i=1;i<=n;++i) cin>>t[i];
    if (build(s)==build(t)) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
}
int main()
{
    // freopen("a.in","r",stdin);
    // freopen("a.out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while (T--) solve();
    return 0;
}
posted on 2026-05-03 17:08  Z_S_R  阅读(2)  评论(0)    收藏  举报