题解:
首先,我们可以用 dfs 在 O(n) 的时间复杂度求出初始状态每个点的权值。
不难发现,一个叶子节点权值的取反会导致根节点的权值取反当且仅当从该叶子节点到根节点这一条链上的每个点的权值都被取反(都被影响到)。而这4种逻辑运算中,NOT 和 XOR 是最简单的,即只要2个儿子中的一个儿子的值被取反,该点的值就会被取反。但 AND 和 OR 存在只修改一个儿子时不会对该点的权值产生影响的情况,这就需要我们进行一下特判。
我们给每个节点开一个 tag 变量, tag = false 的话说明该节点不会随这儿子节点权值的变化而变化,tag=true 则相反。如果一个节点的 tag=false, 那么就没有必要进行特判,直接将所有子节点的 tag 设成 false 即可。
反之,则对左右儿子进行特判,分别下传标记即可。
Code:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1002000 + 3;
int n, ans[maxn], node[maxn], ch[maxn][2], val[maxn];
bool lazy[maxn];
inline int get(char str[]){
if(str[0] == 'I') return 1;
if(str[0] == 'N') return 2;
if(str[0] == 'O') return 3;
if(str[0] == 'A') return 4;
if(str[0] == 'X') return 5;
}
int dfs1(int u)
{
if(node[u] == 1) return val[u] ;
if(node[u] == 2) return (val[u] = !dfs1(ch[u][0]) );
if(node[u] == 3) return (val[u] = (dfs1(ch[u][0]) | dfs1(ch[u][1])) );
if(node[u] == 4) return (val[u] = (dfs1(ch[u][0]) & dfs1(ch[u][1])) );
if(node[u] == 5) return (val[u] = (dfs1(ch[u][0]) ^ dfs1(ch[u][1])) );
}
void dfs2(int u)
{
if(lazy[u] == false) { lazy[ch[u][0]] = lazy[ch[u][1]] = false;}
else{
switch(node[u])
{
case 2:
lazy[ch[u][0]] = true;
break;
case 3:
if(val[ch[u][0]])
lazy[ch[u][1]] = false;
else
lazy[ch[u][1]] = true;
if(val[ch[u][1]])
lazy[ch[u][0]] = false;
else
lazy[ch[u][0]] = true;
break;
case 4:
if(!val[ch[u][0]])
lazy[ch[u][1]] = false;
else
lazy[ch[u][1]] = true;
if(!val[ch[u][1]])
lazy[ch[u][0]] = false;
else
lazy[ch[u][0]] = true;
break;
case 5:
lazy[ch[u][0]] = lazy[ch[u][1]] = true;
break;
}
}
lazy[0] = 0;
if(ch[u][0]) dfs2(ch[u][0]);
if(ch[u][1]) dfs2(ch[u][1]);
}
int main()
{
memset(lazy, 1, sizeof(lazy));
scanf("%d",&n);
for(int i = 1;i <= n; ++i)
{
char str[10];
scanf("%s",str);
node[i] = get(str);
if(node[i] == 1)
scanf("%d",&val[i]);
else if(node[i] == 2)
scanf("%d",&ch[i][0]);
else
scanf("%d%d",&ch[i][0],&ch[i][1]);
}
dfs1(1);
lazy[1] = true;
dfs2(1);
for(int i = 1;i <= n; ++i)
if(node[i] == 1) printf("%d",val[1] ^ lazy[i]);
printf("\n");
return 0;
}