You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
4.2 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010, M = N << 1;
int n; // 变量个数
int w[N]; // 变量参数的值
char c[N]; // 操作符栈
int stk[N], tt; // 数字栈
bool st[N]; // 是不是对
// 邻接表
int e[M], h[N], idx, ne[M];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
// 第一次dfs求原后缀表达式,记录每个节点的计算值
int dfs1(int u) {
if (u <= n) return w[u]; // 叶子节点,返回参数值
if (c[u] == '!') // 如果当前节点是运算符!的话那么它一定只有一个子节点节点号h[u],值e[h[u]],取反返回即可
w[u] = !dfs1(e[h[u]]);
else {
// 与和或
int a = e[h[u]], b = e[ne[h[u]]]; // 取当前节点左儿子和右儿子
if (c[u] == '&')
w[u] = dfs1(a) & dfs1(b); // 左儿子与右儿子的与运算结果 
else
w[u] = dfs1(a) | dfs1(b); // 左儿子与右儿子的或运算结果 
}
return w[u]; // 返回计算结果值
}
// 从根开始,标记哪些节点影响表达式的值
void dfs2(int u) {
st[u] = true; // 因为
if (u <= n) return; // 递归到叶子返回
if (c[u] == '!') { // 取反操作符
dfs2(e[h[u]]); // 前进,继续标记节点
return;
}
int a = e[h[u]], b = e[ne[h[u]]]; // 左右儿子节点号
if (c[u] == '&') { // &运算
if (w[a]) dfs2(b); // 左儿子=1对右子树递归标记
if (w[b]) dfs2(a); // 右儿子=1对左子树递归标记
} else { // |运算
if (!w[a]) dfs2(b); // 左儿子=0递归右子树,右子树中的某些节点变化会对根造成影响
if (!w[b]) dfs2(a); // 右儿子=0递归左儿子,左子树中的某些节点变化会对根造成影响
}
}
int main() {
string s;
getline(cin, s);
cin >> n; // 参数个数
for (int i = 1; i <= n; i++) scanf("%d", &w[i]); // 每个参数对应的数值
memset(h, -1, sizeof h); // 邻接表初始化
// 为了创建一个表达式树就需要给每个节点创建一个编号。现在已知数字节点也就是叶子节点数量是n
// 所以,运算符的编号就是从++m开始的。
int m = n;
// 后缀表达式->栈->建图
// 利用栈进行辅助建图,图才能进行dfs计算
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') continue;
if (s[i] == 'x') {
int k = 0;
i++; // 跳过x
while (i < s.size() && isdigit(s[i])) k = k * 10 + s[i++] - '0';
stk[++tt] = k;
} else if (s[i] == '!') {
c[++m] = s[i]; //++m这个节点表达式树中是s[i]这个操作符,
/* 表达式树:
(1)
(2)
(1)[1~n][n+1~]
(2)char c[],
*/
add(m, stk[tt--]); // 从栈中弹出一个数字,因为是!嘛,树是由上到下的连单向边
stk[++tt] = m; // m节点入栈方便后续构建
} else {
c[++m] = s[i];
add(m, stk[tt--]); // 与!不同需要由m引向两个节点各一条边
add(m, stk[tt--]);
stk[++tt] = m;
}
}
// 计算原式结果
int res = dfs1(m); // 这个m才是根因为是后缀表达式
// 标记哪些节点影响最终结果
dfs2(m);
for (int i = 1; i <= m; i++) {
cout << "i=" << i << ",st[" << i << "]=" << st[i] << ",c[" << i << "]=" << c[i] << endl;
}
int Q;
cin >> Q; // 询问个数
while (Q--) {
int x;
cin >> x; // 修改哪个变量
if (st[x]) // 如果x被打过标记那么它的变化将会影响根节点的值对根节点取反即可
printf("%d\n", !res);
else // 不会影响根节点的值
printf("%d\n", res);
}
return 0;
}