ABC350 FG 题解
本人 Unrated 在开始后 1h 参加,20 分钟过 F,1h 过 G。
F
Overview
唐,史上最水 F。
Description
有一个串 S S S,包含大小写字母,(
和 )
,保证括号匹配。
对于每组匹配括号,从里往外翻转、改变大小写。
比如 ((A)y)x
,可以先变成 (ay)x
,再变成 YAx
。
求最终的 S S S。
Solution
首先确定每个字母的大小写再分治翻转就行了。
类似中缀表达式的求解过程。
O ( n log n ) O(n\log n) O(nlogn)。
Code
void solve(int ll, int r){if(layer[r] & 1){int i = r;while(i >= ll){if(s[i] == ')'){solve(lst[i] + 1, i - 1), i = lst[i] - 1;}else cout << s[i], i--;}}else{int i = ll;while(i <= r){if(s[i] == '('){solve(i + 1, nxt[i] - 1), i = nxt[i] + 1;}else cout << s[i], i++;}}
}void solve(int testcase, ...){init_vars();cin >> s;stack<int> st;for(int i = 0; i < s.length(); i++){if(i) layer[i] = layer[i - 1];if(s[i] == '(') st.push(i), layer[i]++;else if(s[i] == ')'){nxt[st.top()] = i, lst[i] = st.top(), st.pop(); layer[i]--;}else{if(layer[i] & 1){if(s[i] >= 'a') s[i] = s[i] - 'a' + 'A';else s[i] = s[i] - 'A' + 'a';}}}solve(0, s.length() - 1);
}
G
Overview
唐,史上最水 G。
Description
给出 n n n 个点, m m m 个操作, q q q 个操作如下:
1 x y
加边操作;2 x y
求 z z z,满足存在 ( x , z ) (x,z) (x,z) 和 ( y , z ) (y,z) (y,z),没有输出0
。
保证操作后的图是一个森林。
Solution
如果记录每个点的父亲 f x f_x fx,那么可以通过以下方法查询:
- 如果 z z z 是两个点的共同父亲,那么 f x = f y = z f_x=f_y=z fx=fy=z;
- 如果 z z z 是两个点的中间层,令 x x x 为更深的点,那么 f f x = y f_{f_x}=y ffx=y,答案为 f x f_x fx。
合并操作需要更新至少一个子树的 f f f,用启发式合并(按秩合并)即可。
O ( n log n ) O(n\log n) O(nlogn)。
题外话:原来的程序 TLE,本人通过计算理论复杂度和实际计算次数算出了问题。
Code
void dfs(int u, int fat){
// cout << u << " " << fat << endl;
// tott++;fa1[u] = fat;for(auto v : gv[u]){if(v == fat) continue;dfs(v, u);}
}int FindFather(int x){if(fa[x] == x) return x;return fa[x] = FindFather(fa[x]);
}
void Union(int u, int v){u = FindFather(u), v = FindFather(v);if(u == v) return;sz[u] += sz[v];fa[v] = u;
}void solve(int testcase, ...){init_vars();int n, q; scanf("%lld%lld", &n, &q);for(int i = 1; i <= n; i++) fa[i] = i, fa1[i] = 0, sz[i] = 1;int tot = 0, lst = 0;for(int i = 1; i <= q; i++){int a, b, c; scanf("%lld%lld%lld", &a, &b, &c);a = 1 + (((a * (1 + lst)) % 998244353) % 2);b = 1 + (((b * (1 + lst)) % 998244353) % n); c = 1 + (((c * (1 + lst)) % 998244353) % n);
// cout << a << " " << b << " " << c << endl;if(a == 1){if(sz[FindFather(b)] > sz[FindFather(c)]) swap(b, c);
// cout << b << " " << c << endl;tott = 0;dfs(b, c);
// cout << tott << " " << sz[b] << endl;Union(c, b);gv[b].push_back(c);gv[c].push_back(b);}else{
// for(int j = 1; j <= n; j++) cout << sz[FindFather(j)] << " ";
// cout << endl;if(fa1[fa1[b]] == c) lst = fa1[b], printf("%lld\n", fa1[b]);else if(fa1[fa1[c]] == b) lst = fa1[c], printf("%lld\n", fa1[c]);else if(fa1[b] == fa1[c] && fa1[b]) lst = fa1[b], printf("%lld\n", fa1[b]);else lst = 0, printf("0\n");tot++;}
// if(tott > 30000000) return;}
}