原题传送门
我觉得,这道题目主要考察的还是把后缀表达式转成一棵树
然后遍历一遍树求出每个节点的值
然后暴力改动每个节点的值,往上跑,如果某一个时刻新算的值跟原来一样,那么就不用进行下去,否则继续
结果果然只T了一个点,然后我开了O2就过了
Code:
#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
struct Edge{
int to, next;
}edge[maxn << 1];
int num, head[maxn], n, m, stk[maxn], top, val[maxn], sum[maxn], calc[maxn], flag, ans[maxn], tag[maxn], fa[maxn], rt;
char s[maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void addedge(int x, int y){
edge[++num] = (Edge){y, head[x]}, head[x] = num;
}
void build(int u){
if (val[u] < 2) calc[u] = val[u];
else if (val[u] == 2) calc[u] = 0;
else calc[u] = 1;
for (int i = head[u]; i; i = edge[i].next){
int v = edge[i].to;
fa[v] = u;
build(v);
if (val[u] == 2) calc[u] |= calc[v];
else calc[u] &= calc[v];
}
calc[u] ^= tag[u];
}
void dfs(int u){
if (sum[u] == calc[u]){
flag = 1; return;
}
if (u == rt) return;
int v = fa[u], i = head[v];
while (edge[i].to == u) i = edge[i].next;
int w = edge[i].to;
if (val[v] == 2) sum[v] = sum[u] | calc[w];
else sum[v] = sum[u] & calc[w];
sum[v] ^= tag[v];
dfs(v);
}
int main(){
scanf("%s", s + 1);
m = 1e6;
while (!isdigit(s[1])){
char c = s[1];
if (c == 'x'){
int x = 0;
for (int i = 2; i <= strlen(s + 1); ++i) x = (x << 1) + (x << 3) + (s[i] ^ 48);
stk[++top] = x;
} else
if (c == '|' || c == '&'){
--m;
val[m] = c == '|' ? 2 : 3;
addedge(m, stk[top--]), addedge(m, stk[top--]), stk[++top] = m;
} else
if (c == '!') tag[stk[top]] ^= 1;
scanf("%s", s + 1);
}
for (int i = 1; i <= strlen(s + 1); ++i) n = (n << 1) + (n << 3) + (s[i] ^ 48);
rt = stk[top];
for (int i = 1; i <= n; ++i) val[i] = read();
build(rt);
for (int i = 1; i <= n; ++i){
sum[i] = tag[i] ^ val[i] ^ 1, flag = 0;
dfs(i);
if (flag) ans[i] = calc[rt];
else ans[i] = calc[rt] ^ 1;
}
int Q = read();
while (Q--) printf("%d\n", ans[read()]);
return 0;
}