题解 QOJ5246【Nawiasowe podziały】/ SS240121A【Bracket】

  • 题解 SS240122A【Bracket】
  • 题解 QOJ5246【Nawiasowe podziały】
  • 题解 LOJ3919【Nawiasowe podziały】
  • 题解 LGP9266【[PA 2022] Nawiasowe podziały】

题目描述

花花和啾啾是好朋友。他们做完了切糕之后,打算一起切串。

一个括号串的权值是合法括号子串的数量。

现在他们有 \(k\) 要把一个长度为 \(n\) 的括号串 \(S\) 切成 \(k\) 个部分。他们组成了原串的划分。而划分方案的权值为每个部分的括号串权值之和。

花花和啾啾想知道,划分权值最小的方案的权值是多少呢?

\(1\leq k\leq n\leq 5\times 10^5\) ,不保证给定括号串合法。

solution

subtask 1

\(n\leq 300\)

暴力 dp。输出答案数组可以发现答案关于划分段数是凸的,所以直接 wqs 二分可以 \(O(n^2\log n)\)。什么你问怎么算一个区间的合法括号串数?这里写一下我的赛时做法(支持区间滑动):

考虑维护 \(to_r\) 表示使得 \((l,r]\) 合法的最大的 \(l\)。发现,\(i\to to_i\) 这样连边后就剩下一堆链,链上一段区间就合法。每次例如从右边加入一个括号,就一直跳 \(to\),跳到的地方就是一个新的合法括号串。如果需要降低这部分复杂度,可以倍增,但和 dp 转移一样都是 \(O(n^2)\)

\(O(1)\) 计算区间权值(笛卡尔树)

询问 \((L, R]\) 中有多少个合法括号子串。

对原括号串,(\(+1\))\(-1\),做前缀和记为 \(s_i\),那么 \((l,r]\) 合法当且仅当 \(s_l=s_r=\min_{i=l}^rs_i\)

对前缀和建广义笛卡尔树,每个节点代表一个区间 $ [l,r]$,然后拿着一个集合 \(S\)\(S\)\([l,r]\) 中所有最小值的位置,这些位置将区间断开,又分为若干个区间(适当造一些空点),作为儿子。建树直接暴力 ST 表。如果在一个节点上 \(u,v\in S\),然后询问的 \((L,R]\)\((u,v]\in(L,R]\)(注意开区间),那就有 \(1\) 的贡献。所以我们干这么一个事情,我们开始分类讨论。

节点 \([ l,r]\) 有着最小值位置集合 \(S\),对询问 \((L,R]\) 的贡献如下:

  • 一类:\([l,r]\cap [L,R]=\varnothing\)\(0\)
  • 二类:\([L,R]\in[l,r]\)\(\dbinom{|S|}{2}\)
  • 三类:\(L\in[l,r],R\not\in[l,r]\)\(\dbinom{\sum_{x\in S}[x\geq L]}{2}\)
  • 四类:\(L\not\in[l,r],R\in[l,r]\)\(\dbinom{\sum_{x\in S}[x\leq R]}{2}\)
  • 五类:\(L,R\in[l,r]\)\(\dbinom{\sum_{x\in S}[L\leq x\leq R]}{2}\)

这里的每一类贡献都要分的比较仔细,因为后面计算是要分类的。

考虑记 \(u\) 为节点,使得 \(S_{fa[u]}\) 中有 \(L\)\(u\) 就是 \(L\) 断开后左边的节点,可以提前记下;\(v\) 为节点,使得 \(S_{fa[v]}\) 中有 \(R\)\(v\) 就是 \(R\) 断开后右边的节点。记 \(w=\text{lca}(u, v)\)。暴力就是大概是,从 \(u\) 或者 \(v\) 开始跳父亲,然后每个父亲上就算到有多少个最小值能贡献,是 3 / 4 类贡献和旁边子树的 5 类贡献,最后在 \(w\) 上统计 2 / 5 类贡献。具体,记 \(f^k\) 表示 \(k\) 类贡献,\(F^k\) 是一些前缀和。\(F^2_u\) 表示 \(u\) 子树内所有节点的 \(\binom{|S|}{2}\) 的和。\(f^{3/4+5}_u\) 表示 \(u\) 点跳上父亲之后左边或者右边的最小值个数的 binom,加上旁边点的 5 类贡献。\(F^{3/4+5}_u\) 自然就是到根的前缀和。我的天这能算吗。好像真能。答案就是 \(F^{3+5}_u+F^{4+5}_v-F^{3+5}_x-F^{4+5}_y\) 还有一些,其中 \(x,y\)\(u,v\) 跳到 \(w\) 的最后一个节点,剩下的就是 \(w\) 上做 \(F^2\) 的前缀和,以及记录 \(x,y\) 的排名算 \(f^5\)

这个树上 \(k\) 级祖先是什么鬼啊,当然可以长剖,但是我们还可以记录欧拉环游序,ST 表查询完了以后,最左 LCA 的左和最右 LCA 的右就是 \(x,y\)

综上可以 \(O(1)\) 计算区间权值。

\(O(1)\) 计算区间权值(猫树分治)

猫树分治就在建了前缀和,处理了前后缀答案后,我们就考虑跨过区间中点的,大概意思就是考虑左边后缀最小值和右边前缀最小值,在值域上扫下来,在值域上开前缀和数组计算即可。不想细节了。

subtask 4

\(k\leq 30\)

明显满足四边形不等式,所以 dp 转移具有决策单调性。然后不用 wqs 直接做那种分治的决策单调性。\(O(nk\log n)\)。或者听说直接应用石子合并的东西可以 \(O(nk)\)

考虑分治:假如我们已经有划分成 \(d-1\) 段的答案,欲求所有的 \(f_{i,d}\)。考虑欲求 \(f_{[L,R],d}\),现在有效的决策集合是 \([l,r]\)

我们求出 \(f_{mid,d}\) 的值:用 \([l,r]\) 的决策更新。假如找到一个最优决策在 \(p\)

那么我们断定:\([L,mid)\) 的点的决策为 \([l,p]\)\((mid,R]\) 的点的决策为 \([p,r]\)

分析复杂度:一共 \(O(\log n)\) 层,每层平摊 \(O(n)\)

我们的 \(V(l,r)\) 的复杂度如何分析?

考虑左右指针是独立的;考虑对于一个指针,在分治树上的每一个点恰好踩过一次,所以移动量为 \(O(n\log n)\)

所以总复杂度为 \(O(n\log^2 n)\)

subtask 5

\(n\leq 10^5\)。wqs 二分后选择喜欢的决策单调性方法维护(可以考虑队列维护三元组)。\(O(n\log^2n)\)

可参考 https://www.luogu.com.cn/problem/P3515

1D/1D 的 DP 中,维护队列 \((l,r,j)\) 表示 \(f_{i\in[l,r]}\) 都应该由 \(f_j\) 转移而来,\(j\leq l\)。队列中 \(j\) 单调,\([l,r]\) 顺次相连。

  1. 欲求 \(f_i\),那么检查队头 \(r_h<i\)\((l_h,r_h,j_h)\) 的删掉。取出队头进行转移。\(l_h=i\)
  2. 试图插入决策 \(i\) 的时候:
  3. 记队尾为 \((l_t,r_t,j_t)\)
  4. 如果对于 \(f[l_t]\) 来说,\(i\) 优于 \(j_t\),删除队尾,\(pos=l_t\),返回第一步。
  5. 如果对于 \(f[r_t]\) 来说,\(j_t\) 优于 \(i\)\(pos=r_t+1\),去往第五步。
  6. \([l_t,r_t]\) 中二分一个 \(pos\),使得 \(pos\) 往后是 \(i\) 更优,往前是 \(j_t\) 更优,去往第五步。
  7. 插入决策 \((pos,n,i)\)

这样的总复杂度为 \(O(n\log n)\)

(这里有一个误区就是做 \(f_i\) 时从 \(f_{i-1}\) 的决策点开始枚举,这样是假的,因为枚举 \([p_{i-1},i]\) 的时候,你拿到最优决策点,并不知道是最优决策点,只能继续枚举)

subtask 7(正解)

考虑先 wqs 二分。在笛卡尔树上 dp。到了区间 \([l,r]\),我们只考虑区间 \([l,r]\) 中切了 \(i_1,i_2,\cdots,i_k\),那么贡献就是

\[\sum_{j=2}^{k-1}\text{cost}(i_j,i_{j+1},\{2,3,4,5\})+\text{cost}(l,i_1,\{4\})+\text{cost}(i_k,r,\{3\}) \]

\(\text{cost}(l,r,S)\) 表示 \(calc(l,r)\) 只考虑 \(S\) 中的类别的贡献。

然后就是 \(u\) 只需要考虑 5 类贡献。然后就能 dp。然后就斜率优化。有点假,让我去写 2log 先。

code

2log,常数比较大

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
typedef long long LL;
template <int N, class T>
struct STable {
  T f[21][N + 10];
  int lg[N + 10], cnt;
  STable() : cnt(0) { lg[0] = -1; }
  int insert(T x) {
    f[0][++cnt] = x;
    lg[cnt] = lg[cnt >> 1] + 1;
    for (int j = 1; 1 << j <= cnt; j++) {
      int i = cnt - (1 << j) + 1;
      f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
    }
    return cnt;
  }
  T query(int l, int r) {
    int k = lg[r - l + 1];
    return min(f[k][l], f[k][r - (1 << k) + 1]);
  }
};
LL binom2(int n) { return 1ll * n * (n - 1) / 2; }
int n, K, m, a[500010];
char buf[500010];
STable<500010, pair<int, int>> Ta;
vector<int> g[1000010];
int id[500010];
bool cir[1000010];
int build(int l, int r) {
  int u = ++m;
  auto mn = Ta.query(l + 1, r + 1);
  while (l <= r) {
    auto ret = Ta.query(l + 1, r + 1);
    if (ret.first != mn.first) {
      g[u].push_back(build(l, r));
      break;
    }
    int p = ret.second;
    if (l < p) g[u].push_back(build(l, p - 1));
    g[u].push_back(id[p] = ++m);
    cir[id[p]] = true;
    l = p + 1;
  }
  return u;
}
int rnk[1000010], fa[1000010], dep[1000010];
LL F2[1000010], F3[1000010], F4[1000010];
vector<int> pre[1000010];
vector<LL> pF2[1000010];
void dfs2(int u, int fa) {
  ::fa[u] = fa;
  dep[u] = dep[fa] + 1;
  pre[u] = vector<int>(g[u].size());
  pF2[u] = vector<LL>(g[u].size());
  for (int i = 0; i < g[u].size(); i++) {
    rnk[g[u][i]] = i;
    pre[u][i] = (i ? pre[u][i - 1] : 0) + cir[g[u][i]];
  }
  if (!pre[u].empty()) F2[u] = binom2(pre[u].back());
  for (int v : g[u]) dfs2(v, u), F2[u] += F2[v];
  for (int i = 0; i < g[u].size(); i++) {
    pF2[u][i] = (i ? pF2[u][i - 1] : 0) + F2[g[u][i]];
  }
}
void dfs34(int u) {
  if (u > 1) {
    F3[u] += F3[fa[u]] + binom2(pre[fa[u]].back() - (rnk[u] ? pre[fa[u]][rnk[u] - 1] : 0));
    F4[u] += F4[fa[u]] + binom2(pre[fa[u]][rnk[u]]);
  }
  for (LL s = 0, i = 0; i < g[u].size(); i++) {
    F4[g[u][i]] = s;
    s += F2[g[u][i]];
  }
  for (LL s = 0, i = (int)g[u].size() - 1; i >= 0; i--) {
    F3[g[u][i]] = s;
    s += F2[g[u][i]];
  }
  for (int v : g[u]) dfs34(v);
}
int dfnf[1000010], dfnb[1000010];
int rnkf[1000010], rnkb[1000010];
STable<1000010, pair<int, int>> Tf, Tb;
void dfsf(int u) { 
  dfnf[u] = Tf.insert({dep[u], -(Tf.cnt + 1)}); 
  rnkf[dfnf[u]] = u;
  for (int i = 0; i < g[u].size(); i++) {
    dfsf(g[u][i]);
  }
}
void dfsb(int u) {
  dfnb[u] = Tb.insert({dep[u], -(Tb.cnt + 1)}); 
  rnkb[dfnb[u]] = u;
  for (int i = (int)g[u].size() - 1; i >= 0; i--) {
    dfsb(g[u][i]);
  }
}
LL calc(int l, int r) {
//--l;
//(l, r]
  assert(l < r);
  int u = id[l], v = id[r];
  int y = rnkf[-Tf.query(dfnf[u], dfnf[v]).second];
  int x = rnkb[-Tb.query(dfnb[v], dfnb[u]).second];
  int w = fa[x];
  return F3[u] - F3[x] + F4[v] - F4[y]
    + binom2(pre[w][rnk[y]] - (rnk[x] ? pre[w][rnk[x] - 1] : 0))
    - pF2[w][rnk[x]] + (rnk[y] ? pF2[w][rnk[y] - 1] : 0);
}
pair<LL, int> dp(LL ext) {
  struct node {
    int l, r, j;
  };
  static node q[500010];
  static LL f[500010], g[500010];
  int L = 1, R = 0;
  q[++R] = {1, n, 0};
  auto cmp = [&](int i, int j, int k) {
    auto vi = f[i] + calc(i, k), vj = f[j] + calc(j, k);
    return vi == vj ? g[i] > g[j] : vi < vj;
  };
  for (int i = 1; i <= n; i++) {
    debug("i = %d\n", i);
    while (L <= R && q[L].r < i) ++L;
    assert(L <= R);
    debug("choose j = %d\n", q[L].j);
    f[i] = f[q[L].j] + calc(q[L].j, i) + ext;
    g[i] = g[q[L].j] + 1;
    while (L <= R && (q[R].l = max(q[R].l, i + 1)) && (q[R].l > q[R].r || cmp(i, q[R].j, q[R].l))) --R;
    int pos = i;
    if (L <= R) {
      int l = q[R].l, r = q[R].r;
      pos = r + 1;
      for (int mid = (l + r) >> 1; l <= r; mid = (l + r) >> 1) {
        if (cmp(i, q[R].j, mid)) pos = mid, r = mid - 1;
        else l = mid + 1;
      }
    }
    debug("pos = %d\n", pos);
    if (pos <= n) q[R].r = pos - 1, q[++R] = {pos, n, i};
#ifdef LOCAL
    for (int j = 0; j < i; j++) if (f[j] + calc(j, i) + ext < f[i]) f[i] = f[j] + calc(j, i) + ext, g[i] = g[j] + 1, debug("upd by %d\n", j);
    else if (f[j] + calc(j, i) + ext == f[i] && g[i] < g[j] + 1) g[i] = max(g[i], g[j] + 1), debug("update by %d\n", j);
    for (int j = L; j <= R; debug("[%d->%d]", q[j].l, q[j].r),j++) for (int t = q[j].l; t <= q[j].r; t++) debug("%d|", q[j].j);debug("\n");
#endif
  }
  return make_pair(f[n], g[n]);
}
LL binary(LL L, LL R) {
  LL ans = -1;
  for (LL mid = (L + R) >> 1; L <= R; mid = (L + R) >> 1) {
    auto res = dp(mid);
    debug("mid = %lld, res = {%d, %d}\n", mid, res.first, res.second);
    if (res.second < K) R = mid - 1;
    else L = mid + 1, ans = res.first - K * mid;
  }
  return ans;
}
int main() {
#ifndef LOCAL
  cin.tie(nullptr)->sync_with_stdio(false);
#endif  

freopen("bracket.in", "r", stdin), freopen("bracket.out", "w", stdout);
  cin >> n >> K >> buf;
  for (int i = 1; i <= n; i++) a[i] = a[i - 1] + (buf[i - 1] == '(' ? +1 : -1);
  for (int i = 0; i <= n; i++) Ta.insert({a[i], i});
  build(0, n);
  dfs2(1, 0);
  dfsf(1), dfsb(1);
  dfs34(1);
  cout << binary(0, 1e12) << endl;
  return 0;
}

1log 斜率优化正解

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
typedef long long LL;
template <int N, class T>
struct STable {
  T f[21][N + 10];
  int lg[N + 10], cnt;
  STable() : cnt(0) { lg[0] = -1; }
  int insert(T x) {
    f[0][++cnt] = x;
    lg[cnt] = lg[cnt >> 1] + 1;
    for (int j = 1; 1 << j <= cnt; j++) {
      int i = cnt - (1 << j) + 1;
      f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
    }
    return cnt;
  }
  T query(int l, int r) {
    int k = lg[r - l + 1];
    return min(f[k][l], f[k][r - (1 << k) + 1]);
  }
};
LL binom2(int n) { return 1ll * n * (n - 1) / 2; }
int n, K, m, a[500010];
char buf[500010];
STable<500010, pair<int, int>> Ta;
vector<int> g[1000010];
int id[500010];
bool cir[1000010];
int build(int l, int r) {
  int u = ++m;
  auto mn = Ta.query(l + 1, r + 1);
  while (l <= r) {
    auto ret = Ta.query(l + 1, r + 1);
    if (ret.first != mn.first) {
      g[u].push_back(build(l, r));
      break;
    }
    int p = ret.second;
    if (l < p) g[u].push_back(build(l, p - 1));
    g[u].push_back(id[p] = ++m);
    cir[id[p]] = true;
    l = p + 1;
  }
  return u;
}
int rnk[1000010], fa[1000010], dep[1000010];
LL F2[1000010], F3[1000010], F4[1000010];
vector<int> pre[1000010];
vector<LL> pF2[1000010];
void dfs2(int u, int fa) {
  ::fa[u] = fa;
  dep[u] = dep[fa] + 1;
  pre[u] = vector<int>(g[u].size());
  pF2[u] = vector<LL>(g[u].size());
  for (int i = 0; i < g[u].size(); i++) {
    rnk[g[u][i]] = i;
    pre[u][i] = (i ? pre[u][i - 1] : 0) + cir[g[u][i]];
  }
  if (!pre[u].empty()) F2[u] = binom2(pre[u].back());
  for (int v : g[u]) dfs2(v, u), F2[u] += F2[v];
  for (int i = 0; i < g[u].size(); i++) {
    pF2[u][i] = (i ? pF2[u][i - 1] : 0) + F2[g[u][i]];
  }
}
void dfs34(int u) {
  if (u > 1) {
    F3[u] += binom2(pre[fa[u]].back() - (rnk[u] ? pre[fa[u]][rnk[u] - 1] : 0));
    F4[u] += binom2(pre[fa[u]][rnk[u]]);
  }
  for (LL s = 0, i = 0; i < g[u].size(); i++) {
    F4[g[u][i]] = s;
    s += F2[g[u][i]];
  }
  for (LL s = 0, i = (int)g[u].size() - 1; i >= 0; i--) {
    F3[g[u][i]] = s;
    s += F2[g[u][i]];
  }
  for (int v : g[u]) dfs34(v);
}
/*
   LL calc(int l, int r) {
//--l;
//(l, r]
assert(l < r);
int u = id[l], v = id[r];
int y = rnkf[-Tf.query(dfnf[u], dfnf[v]).second];
int x = rnkb[-Tb.query(dfnb[v], dfnb[u]).second];
int w = fa[x];
return F3[u] - F3[x] + F4[v] - F4[y]
+ binom2(pre[w][rnk[y]] - (rnk[x] ? pre[w][rnk[x] - 1] : 0))
- pF2[w][rnk[x]] + (rnk[y] ? pF2[w][rnk[y] - 1] : 0);
}
*/
struct dot {
  LL x, y;
  int fd;
  bool operator<(const dot& b) const { return y != b.y ? y < b.y : fd > b.fd; }
  dot operator-(dot b) const { return {x - b.x, y - b.y}; }
  friend LL cross(dot a, dot b) { return a.x * b.y - a.y * b.x; }
};
template <int N>
struct convexHull {
  dot q[N + 10];
  int L, R;
  void clear() { L = 1, R = 0; }
  convexHull() { clear(); }
  void addPoint(LL x, LL y, int fd) {
    dot t = {x, y, fd};
    while (L < R) {
      auto ret = cross(t - q[R], q[R - 1] - q[R]);
      if (ret) {
        if (ret < 0) --R;
        else break;
      } else {
        if (t.x != q[R].x) {
          --R;
        } else {
          t = min(t, q[R--]);
          t = min(t, q[R--]);
        }
      }
    }
    if (L == R && q[R].x == t.x) t = min(t, q[R--]);
    q[++R] = t;
  }
  auto query(LL k) {
    while (L < R && cross(q[L + 1] - q[L], {1, k}) > 0) ++L;
    auto res = make_pair(q[L].y - k * q[L].x, q[L].fd);
    if (L < R && !cross(q[L + 1] - q[L], {1, k})) res.second = max(res.second, q[L + 1].fd);
    return res;
  }
  bool empty() { return L > R; }
};
bool must[2][1000010];
LL f[1000010], h[1000010];
int fd[1000010], fh[1000010];
void dp(int u, LL ext) {
  f[u] = 1e18;
  fd[u] = 0;
  if (cir[u]) return f[u] = ext, fd[u] = 1, void();
  for (int v : g[u]) dp(v, ext);
  static convexHull<1000010> C;
  C.clear();
  for (int i = 0; i < g[u].size(); i++) {
    if (must[0][u] && i) h[i] = 1e18, fh[i] = 0;
    else h[i] = f[g[u][i]] + F4[g[u][i]], fh[i] = fd[g[u][i]];
    /*
       for (int j = 0; j < i; j++) {
       auto tmp = h[j] + binom2(pre[u][i] - (j ? pre[u][j - 1] : 0)) + pF2[u][i - 1] - pF2[u][j] + f[g[u][i]];
       debug("u = %d, i = %d, j = %d, tmp = %lld\n", u, i, j, tmp);
       if (h[i] > tmp) h[i] = tmp, fh[i] = fh[j] + fd[g[u][i]];
       else if (h[i] == tmp && fh[i] < fh[j] + fd[g[u][i]]) fh[i] = fh[j] + fd[g[u][i]];
       */
    LL a = pre[u][i], b = i ? pre[u][i - 1] : 0;
    // 2h[i] = 2h[j] + (a - b[j]) * (a - b[j] - 1) + 2pF2[u][i - 1] - 2pF2[u][j] + 2f[g[u][i]]
    // (a - b[j]) * (a - b[j] - 1) = (a - b[j]) ^ 2 - a + b[j] = a ^ 2 - 2ab[j] + b[j] ^ 2 - a + b[j]
    if (!C.empty()) {
      auto ret = C.query(a);
      ret.first += a * a - a + 2 * pF2[u][i - 1] + 2 * f[g[u][i]];
      assert(ret.first % 2 == 0);
      ret.first >>= 1;
      ret.second += fd[g[u][i]];
      if (h[i] > ret.first) h[i] = ret.first, fh[i] = ret.second;
      else if (h[i] == ret.first) fh[i] = max(fh[i], ret.second);
    }
    if (h[i] < 1e18) C.addPoint(b * 2, 2 * h[i] + b * b + b - 2 * pF2[u][i], fh[i]);
    if (!must[1][u] || i + 1 == g[u].size()) {
      if (f[u] > h[i] + F3[g[u][i]]) f[u] = h[i] + F3[g[u][i]], fd[u] = fh[i];
      else if (f[u] == h[i] + F3[g[u][i]] && fd[u] < fh[i]) fd[u] = fh[i];
    }
  }
  debug("f[%d] = %lld, fd[%d] = %d\n", u, f[u], u, fd[u]); 
}
auto dp(LL ext) {
  debug("ext = %lld\n", ext);
  dp(1, ext);
  return make_pair(f[1] - ext, fd[1] - 1);
}
LL binary(LL L, LL R) {
  LL ans = -1;
  for (LL mid = (L + R) >> 1; L <= R; mid = (L + R) >> 1) {
    auto res = dp(mid);
    debug("mid = %lld, res = {%lld, %d}\n", mid, res.first, res.second);
    if (res.second < K) R = mid - 1;
    else L = mid + 1, ans = res.first - K * mid;
  }
  return ans;
}
int main() {
#ifndef LOCAL
  cin.tie(nullptr)->sync_with_stdio(false);
#ifndef NF

  freopen("bracket.in", "r", stdin);
  freopen("bracket.out", "w", stdout);
#endif
#endif  
  cin >> n >> K >> buf;
  for (int i = 1; i <= n; i++) a[i] = a[i - 1] + (buf[i - 1] == '(' ? +1 : -1);
  for (int i = 0; i <= n; i++) Ta.insert({a[i], i});
  build(0, n);
  dfs2(1, 0);
  dfs34(1);
  for (int p = id[0]; p; p = fa[p]) must[0][p] = true;
  for (int p = id[n]; p; p = fa[p]) must[1][p] = true;
  for (int i = 0; i <= n; i++) debug("id[%d] = %d\n", i, id[i]);
  for (int i = 1; i <= m; i++) {
    for (int v : g[i]) debug("(%d, %d)\n", i, v);
  }
  cout << binary(0, 1e12) << endl;
return 0;
}
posted @ 2024-01-22 15:59  caijianhong  阅读(24)  评论(0编辑  收藏  举报