- 分享
DAY04 T3代码
- @ 2024-10-5 16:46:01
纯暴力
#include <bits/stdc++.h>
#define int long long
#define qwq ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
/*
T3:
如何用数组存储树:
假设当前节点下标是 i ,那么它的左孩子的下标 i*2,右孩子的下标 i*2+1
一个字符集,它能组成回文的条件是:所有字符中,最多只能有一个字符出现的次数是奇数
统计以每个节点作为根节点的树,字符的出现次数
统计以这个节点为根的树,字符的出现总数
*/
const int N = 1e5+5;
int n, q, cnt[30], res;
char tree[N];
void dfs(int i) {
cnt[tree[i]-'a']++; // 统计当前的
if (i*2 <=n) dfs(i*2);
if (i*2+1 <=n) dfs(i*2+1);
}
bool check() {
// 统计cnt数组中的奇偶数量
int sum = 0;
for (int i=0; i<26; i++) {
sum += cnt[i]%2;
}
return sum <= 1;
}
void solve() {
res = 0;
for (int i=1; i<=n; i++) {
memset(cnt, 0, sizeof cnt);
dfs(i);
// 处理cnt里的所有情况,统计出现次数的奇偶数量
if (check()) res++;
}
cout << res << '\n';
}
signed main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
qwq;
cin >> n >> q;
for (int i=1; i<=n; i++) cin >> tree[i];
solve();
while (q--) {
int x;
char c;
cin >> x >> c;
tree[x] = c;
solve();
}
return 0;
}
利用桶记录每一个节点的字符数量,这样只需要dfs一次。
#include <bits/stdc++.h>
#define int long long
#define qwq ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
/*
T3:
如何用数组存储树:
假设当前节点下标是 i ,那么它的左孩子的下标 i*2,右孩子的下标 i*2+1
一个字符集,它能组成回文的条件是:所有字符中,最多只能有一个字符出现的次数是奇数
统计以每个节点作为根节点的树,字符的出现次数
统计以这个节点为根的树,字符的出现总数
*/
const int N = 1e5+5;
int n, q, cnt[N][30], res;
// cnt[i][j] 表示的是以i节点为根的树,字母j出现的次数
char tree[N];
void dfs(int i) {
cnt[i][tree[i]-'a']++; // 统计当前的
if (i*2 <=n) {
dfs(i*2); // cnt[i*2]
for (int j=0; j<26; j++) cnt[i][j] += cnt[i*2][j];
}
if (i*2+1 <=n) {
dfs(i*2+1); // cnt[i*2+1]
for (int j=0; j<26; j++) cnt[i][j] += cnt[i*2+1][j];
}
}
bool check(int i) {
int sum = 0;
for (int j=0; j<26; j++) {
sum += (cnt[i][j] % 2);
}
return sum <= 1;
}
void solve() {
res = 0;
for (int i=1; i<=n; i++) {
if (check(i)) res++;
}
cout << res << '\n';
}
signed main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
qwq;
cin >> n >> q;
for (int i=1; i<=n; i++) cin >> tree[i];
dfs(1); // 遍历根节点
solve();
while (q--) {
int x;
char c;
cin >> x >> c;
tree[x] = c;
memset(cnt, 0, sizeof cnt);
dfs(1);
solve();
}
return 0;
}
正解:
#include <bits/stdc++.h>
#define int long long
#define qwq ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
/*
T3:
如何用数组存储树:
假设当前节点下标是 i ,那么它的左孩子的下标 i*2,右孩子的下标 i*2+1
一个字符集,它能组成回文的条件是:所有字符中,最多只能有一个字符出现的次数是奇数
统计以每个节点作为根节点的树,字符的出现次数
统计以这个节点为根的树,字符的出现总数
*/
const int N = 1e5+5;
int n, q, cnt[N][30], res;
// cnt[i][j] 表示的是以i节点为根的树,字母j出现的次数
int mask[N]; // mask[i]标记节点i目前是否是满足答案的
char tree[N];
void dfs(int i) {
cnt[i][tree[i]-'a']++; // 统计当前的
if (i*2 <=n) {
dfs(i*2); // cnt[i*2]
for (int j=0; j<26; j++) cnt[i][j] += cnt[i*2][j];
}
if (i*2+1 <=n) {
dfs(i*2+1); // cnt[i*2+1]
for (int j=0; j<26; j++) cnt[i][j] += cnt[i*2+1][j];
}
}
bool check(int i) {
int sum = 0;
for (int j=0; j<26; j++) {
sum += (cnt[i][j] % 2);
}
return sum <= 1;
}
void solve() {
res = 0;
for (int i=1; i<=n; i++) {
if (check(i)) {
res++;
mask[i] = 1; // 标记节点i是满足答案的
}
}
cout << res << '\n';
}
void up(int x, char last, char c) {
while (x > 0) {
// x是被修改的字母的下标,c是新的字母
cnt[x][c-'a']++;
cnt[x][last-'a']--;
// 如果之前x不满足答案,现在满足答案,res++;
if (check(x)) {
if (mask[x] == 0) res++;
mask[x] = 1;
}
else {
if (mask[x] == 1) res--;
mask[x] = 0;
}
// 如果之前x满足答案,但现在不满足答案,res--;
x /= 2;
}
}
signed main() {
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);
qwq;
cin >> n >> q;
for (int i=1; i<=n; i++) cin >> tree[i];
dfs(1); // 遍历根节点
solve();
while (q--) {
int x;
char c;
cin >> x >> c;
up(x, tree[x], c);
tree[x] = c;
cout << res << '\n';
}
return 0;
}
1 条评论
-
彭诗皓 LV 5 @ 2024-10-5 16:47:31两个老师都发了答案
- 1