题目:P7073 [CSP-J2020] 表达式 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目看上方链接
乍一看这道题,大家都能想到是表达式树的题。
难点:在建好树、算好值后某一未知数取反后不重新算,如何更新答案?
- 第一次算的时候记录每一个子树的值(之后都叫vl)。
- 只有取反的未知数的祖先(包括他自己)的vl才有可能更改。
- 利用②,更新答案时向上追溯祖先并求出更新后对应的vl,我叫他tt。
- 如果追溯到某一祖先t==vl直接跳出,否则vl=t,继续追溯。
所以,问题完美解决,时间复杂度,代码在下面
tree中:
- fa表示父亲节点,sl、sr表示的是孩子,“&”“|”有两个儿子(用到sl、sr),“!”只有一个(用到sl),未知数没有后代。
- vl就是上文提到的答案值。
- m表示杂乱信息:{kng是类型:kng==true时表示未知数(此时id是x后面的数);hng==false时表示符号(此时id是字符串中所对应的位置下标)}。
- 每个节点编号是cnt(即tree[cnt]).
st是建树时用到的栈(下标是ed),w[i]表示xi对应的cnt,r是树根
dfs用来求vl
#include<bits/stdc++.h>
#define N 110000
#define SL 1100000
using namespace std;
struct Treenode {
struct Inf {
int id;
bool knd;
};
Inf m;
int fa, sl, sr;
bool vl;
};
Treenode tree[SL] = {};
int st[SL] = {}, w[N] = {}, cnt = 0, ed = 0, n = 0, q = 0, r = 0;
char s[SL] = {};
inline void dfs(int node);
int main() {
cin.getline(s + 1, SL);
int l = strlen(s + 1);
s[l + 1] = ' ';
s[l + 1] = '\0';
l++;
for (int i = 1; i <= l; i++) {
if (s[i] == '&' || s[i] == '|') {
cnt++;
tree[cnt].m.knd = true;
tree[cnt].m.id = i;
tree[cnt].sl = st[ed - 1];
tree[cnt].sr = st[ed];
tree[st[ed - 1]].fa = tree[st[ed]].fa = cnt;
ed--;
st[ed] = cnt;
} else {
if (s[i] == '!') {
cnt++;
tree[cnt].m.knd = true;
tree[cnt].m.id = i;
tree[cnt].sl = st[ed];
tree[st[ed]].fa = cnt;
st[ed] = cnt;
} else {
if (s[i] == 'x') {
int sum = 0;
for (i = i + 1; s[i] != ' '; i++) {
sum = sum * 10 + s[i] - '0';
}
cnt++;
w[sum] = cnt;
tree[cnt].m.knd = false;
tree[cnt].m.id = sum;
ed++;
st[ed] = cnt;
}
}
}
if (i == l - 1) {
r = cnt;
}
}
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int opt = 0;
scanf("%d", &opt);
tree[w[i]].vl = opt;
}
dfs(r);
scanf("%d", &q);
for (int i = 1; i <= q; i++) {
int x = 0;
scanf("%d", &x);
tree[w[x]].vl = not tree[w[x]].vl;
int t = w[x];
while (t != r) {
t = tree[t].fa;
bool tp = tree[t].vl;
if (s[tree[t].m.id] == '&') {
tree[t].vl = tree[tree[t].sl].vl and tree[tree[t].sr].vl;
} else {
if (s[tree[t].m.id] == '|') {
tree[t].vl = tree[tree[t].sl].vl or tree[tree[t].sr].vl;
} else {
tree[t].vl = not tree[tree[t].sl].vl;
}
}
if (tp == tree[t].vl) {
break;
}
}
cout << tree[r].vl;
tree[w[x]].vl = not tree[w[x]].vl;
t = w[x];
while (t != r) {
t = tree[t].fa;
bool tp = tree[t].vl;
if (s[tree[t].m.id] == '&') {
tree[t].vl = tree[tree[t].sl].vl and tree[tree[t].sr].vl;
} else {
if (s[tree[t].m.id] == '|') {
tree[t].vl = tree[tree[t].sl].vl or tree[tree[t].sr].vl;
} else {
tree[t].vl = not tree[tree[t].sl].vl;
}
}
if (tp == tree[t].vl) {
break;
}
}
printf("\n");
}
return 0;
}
inline void dfs(int node) {
if (tree[node].m.knd == true) {
if (s[tree[node].m.id] == '&') {
dfs(tree[node].sl);
dfs(tree[node].sr);
tree[node].vl = tree[tree[node].sl].vl and tree[tree[node].sr].vl;
} else {
if (s[tree[node].m.id] == '|') {
dfs(tree[node].sl);
dfs(tree[node].sr);
tree[node].vl = tree[tree[node].sl].vl or tree[tree[node].sr].vl;
} else {
if (s[tree[node].m.id] == '!') {
dfs(tree[node].sl);
tree[node].vl = not tree[tree[node].sl].vl;
}
}
}
}
}
这个代码或许有些长,但是跑得不慢。
如果有建议欢迎大家给建议。
希望大家不要直接把我代码直接交上去,还是要学会了自己写一遍,谢谢配合。