给定有 n n n 个点、边权为 1 1 1 的树的括号序列 s s s( ∣ s ∣ = 2 n − 2 \mid s \mid ~= 2n - 2 ∣s∣ =2n−2),再有 q q q 次操作,每次操作交换 s l , s r s_l, s_r sl,sr,每次操作后输出对应的树的直径。 ( n , q ≤ 1 0 5 ) (n, q \leq 10^5) (n,q≤105)
https://codeforces.com/contest/1149/problem/C
对于静态的树直径,有两次 d f s dfs dfs、树形 d p dp dp 的解法,这里括号序列也可以导出对应的求解方法,左括号对应深度 + 1 +1 +1,右括号对应深度减 − 1 -1 −1,则预处理出前缀和即为深度数组 d e p dep dep。 d i s ( u , v ) = d e p [ u ] + d e p [ v ] − 2 ∗ d e p [ l c a ( u , v ) ] dis(u, v) = dep[u] + dep[v] - 2 * dep[lca(u, v)] dis(u,v)=dep[u]+dep[v]−2∗dep[lca(u,v)],其中, d e p [ l c a ( u , v ) ] = min { d e p [ l ] } dep[lca(u, v)] = \min\{dep[l]\} dep[lca(u,v)]=min{dep[l]}, l l l 为 u , v u, v u,v 任一对应括号位置之间的对应点,从左到右扫过去,维护 max { d e p [ u ] } , max { d e p [ u ] − 2 ∗ d e p [ l ] } , max { d e p [ u ] + d e p [ v ] − 2 ∗ d e p [ l ] } \max\{dep[u]\}, \max\{dep[u] - 2 * dep[l]\}, \max\{dep[u] + dep[v] - 2 * dep[l]\} max{dep[u]},max{dep[u]−2∗dep[l]},max{dep[u]+dep[v]−2∗dep[l]},则可以 O ( n ) O(n) O(n) 得到树直径。
为了支持修改操作,使用线段树区间合并来动态维护,具体需要分别维护左右(前后缀)的对应信息。
#include
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
char s[maxn];
int dep[maxn];
int n, q;
struct SegTree{
int ans[maxn << 2], mxu[maxn << 2], mxl[maxn << 2], mxul[maxn << 2], mxlv[maxn << 2], add[maxn << 2];
void pushUp(int rt){
mxu[rt] = max(mxu[lson], mxu[rson]);
mxl[rt] = max(mxl[lson], mxl[rson]);
mxul[rt] = max(max(mxul[lson], mxul[rson]), mxu[lson] + mxl[rson]);
mxlv[rt] = max(max(mxlv[lson], mxlv[rson]), mxl[lson] + mxu[rson]);
ans[rt] = max(max(ans[lson], ans[rson]), max(mxu[lson] + mxlv[rson], mxul[lson] + mxu[rson]));
}
void build(int l, int r, int rt){
add[rt] = 0;
if(l == r){
ans[rt] = 0;
mxu[rt] = dep[l], mxl[rt] = -2 * dep[l], mxul[rt] = mxlv[rt] = -dep[l];
return;
}
int mid = gmid;
build(l, mid, lson);
build(mid + 1, r, rson);
pushUp(rt);
}
void pushDown2(int rt, int son){
add[son] += add[rt];
mxu[son] += add[rt];
mxl[son] += -2 * add[rt];
mxul[son] += -add[rt];
mxlv[son] += -add[rt];
}
void pushDown(int rt){
pushDown2(rt, lson);
pushDown2(rt, rson);
add[rt] = 0;
}
void update(int l, int r, int rt, int L, int R, int val){
if(l >= L && r <= R){
add[0] = val;
pushDown2(0, rt);
return;
}
int mid = gmid;
pushDown(rt);
if(L <= mid) update(l, mid, lson, L, R, val);
if(R > mid) update(mid + 1, r, rson, L, R, val);
pushUp(rt);
}
} tr;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin >> n >> q;
cin >> s + 1;
n = 2 * (n - 1);
for(int i = 1; i <= n; ++i){
dep[i] = dep[i - 1] + (s[i] == '(' ? 1 : -1);
}
tr.build(1, n, 1);
cout << tr.ans[1] << "\n";
while(q--){
int l, r; cin >> l >> r;
if(l > r) swap(l, r);
if(s[l] == s[r]) continue;
tr.update(1, n, 1, l, r - 1, s[l] == '(' ? -2 : 2);
cout << tr.ans[1] << "\n";
swap(s[l], s[r]);
}
return 0;
}