'commit'
This commit is contained in:
87
TangDou/CSP-J/J2_2020/3_Tree_1.cpp
Normal file
87
TangDou/CSP-J/J2_2020/3_Tree_1.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
const int N = 1000010, M = N << 1;
|
||||
#define ls e[h[u]]
|
||||
#define rs e[ne[h[u]]]
|
||||
|
||||
int n; // n个变量
|
||||
int a[N]; // 每个变量对应的数值
|
||||
char c[N]; // 操作符
|
||||
stack<int> stk; // 模拟栈
|
||||
|
||||
// 链式前向星
|
||||
int e[M], h[N], idx, w[M], ne[M];
|
||||
void add(int a, int b, int c = 0) {
|
||||
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
|
||||
}
|
||||
|
||||
// 表示式求值
|
||||
int dfs(int u) {
|
||||
if (u <= n) return a[u]; // 如果是叶子,是变量,是数值,返回真实值
|
||||
if (c[u] == '!')
|
||||
a[u] = !dfs(ls); //! 只有一个儿子,所以e[h[u]]就是儿子的节点号,对儿子返回的值取反就是当前节点的返回值,同时实现了记忆化
|
||||
else {
|
||||
//&和|有两个儿子,分别是e[h[u]]和e[ne[h[u]]]
|
||||
if (c[u] == '&')
|
||||
a[u] = dfs(ls) & dfs(rs); // 计算
|
||||
else
|
||||
a[u] = dfs(ls) | dfs(rs); // 计算
|
||||
}
|
||||
return a[u]; // 返回
|
||||
}
|
||||
|
||||
// https://www.luogu.com.cn/problem/P7073
|
||||
// 20个测试点,可以过掉6个
|
||||
int main() {
|
||||
memset(h, -1, sizeof h); // 初始化链式前向星
|
||||
string s;
|
||||
getline(cin, s); // 读整行字符串,带空格的
|
||||
cin >> n;
|
||||
for (int i = 1; i <= n; i++) cin >> a[i]; // x1,x2,x3的真实值, 0 1 0 0 1
|
||||
|
||||
// 数字占了前n个节点,比如x1占用了1号节点,x2占用了2号节点
|
||||
// n+1开始留给操作符
|
||||
int idx = n;
|
||||
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
if (s[i] == ' ') continue; // 放过空格
|
||||
if (s[i] == 'x') { // 发现是变量标识 x234
|
||||
int k = 0;
|
||||
i++;
|
||||
while (i < s.size() && isdigit(s[i]))
|
||||
k = k * 10 + s[i++] - '0'; // 取得是 x?,比如?=124
|
||||
stk.push(k); // x124存到图中,节点号就是124
|
||||
} else if (s[i] == '!') {
|
||||
c[++idx] = s[i]; // 记录操作符数组,n+1是第一个操作符对应的树中节点号
|
||||
add(idx, stk.top()); // 操作符向数字连一条边
|
||||
stk.pop();
|
||||
stk.push(idx); // 将操作符也要入栈
|
||||
} else { // 如果是 & 或 |
|
||||
c[++idx] = s[i]; // 记录idx号节点是 & 或 | 或 !
|
||||
int a = stk.top();
|
||||
stk.pop();
|
||||
int b = stk.top();
|
||||
stk.pop();
|
||||
add(idx, a), add(idx, b); // 1托2建边
|
||||
stk.push(idx); // 将操作符也要入栈
|
||||
}
|
||||
}
|
||||
|
||||
// 最后一个入栈的是根,根是一个操作符,叶子都是变量,是数值
|
||||
int root = stk.top();
|
||||
|
||||
int q;
|
||||
cin >> q;
|
||||
while (q--) {
|
||||
int x;
|
||||
cin >> x;
|
||||
// 取反
|
||||
a[x] = !a[x];
|
||||
// 输出
|
||||
cout << dfs(root) << endl;
|
||||
// 还原现场
|
||||
a[x] = !a[x];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user