题目链接
题意:给定一个二叉树和四个字符,IN是指在叶子节点输入,AND是两个儿子节点按位&,OR是两个儿子节点按位|,XOR是两个儿子节点按位^,NOT是儿子节点异或1,根据叶子节点输入的值,一步步由底向上递推出答案,现在要求每个叶子节点改变值,求该叶子节点值改变后的根节点的值。
思路:一个个枚举不太现实,我么可以做到的就是判断出哪个叶子节点改变后对会根节点产生变化标记为vis【x】=1,叶子节点改变后也不影响根节点值得我们不用管(根据这个特性,只需判断vis【x】与根节点相异或,因为0异或谁都不会变),那么剩下得就是细节文字,当递归到了一个节点,根据AND,XOR,OR的特性判断那个节点可能改变了,这里列举一下AND,其他都差不多,当一个节点是AND,我们想想什么情况下它的儿子改变会影响它的值,如果两个儿子节点都是1,那么显然我们肯定两边都要递归,因为两个儿子都有改变的嫌疑,如果儿子有一个1和一个0,我们递归结果为0的节点(因为这个0改变了会改变当前节点的值,本来0&10,1&11),如果两个儿子都是0,显然不管两个儿子谁变了都不会影响答案。其他的根据位运算规律仔细思考下应该都能出来,细心一点就行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+1;
int n,k=0,num[maxn],vis[maxn];
struct node{
int l,r,val;
}tree[maxn];
int ans[maxn];
char s[5];
int dfs1(int x)
{
if(tree[x].val>=0) return ans[x]=tree[x].val;
else if(tree[x].val==-1) return ans[x]=dfs1(tree[x].l)&dfs1(tree[x].r);
else if(tree[x].val==-2) return ans[x]=dfs1(tree[x].l)|dfs1(tree[x].r);
else if(tree[x].val==-3) return ans[x]=dfs1(tree[x].l)^dfs1(tree[x].r);
else if(tree[x].val==-4) return ans[x]=dfs1(tree[x].l)^1;
}
void dfs2(int x)
{
if(tree[x].val>=0) {
vis[x]=1;return ;
}
else if(tree[x].val==-1)
{
if(ans[tree[x].l]&ans[tree[x].r]) dfs2(tree[x].l),dfs2(tree[x].r);
else if(ans[tree[x].l]|ans[tree[x].r]) dfs2(ans[tree[x].l]?tree[x].r:tree[x].l);
}
else if(tree[x].val==-2)
{
if(ans[tree[x].l]&ans[tree[x].r]) return ;
else if(ans[tree[x].l]|ans[tree[x].r]) dfs2(ans[tree[x].l]?tree[x].l:tree[x].r);
else dfs2(tree[x].l),dfs2(tree[x].r);
}
else if(tree[x].val==-3) dfs2(tree[x].l),dfs2(tree[x].r);
else if(tree[x].val==-4) dfs2(tree[x].l);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%s",s);
if(s[0]=='A') scanf("%d%d",&tree[i].l,&tree[i].r),tree[i].val=-1;
else if(s[0]=='O') scanf("%d%d",&tree[i].l,&tree[i].r),tree[i].val=-2;
else if(s[0]=='X') scanf("%d%d",&tree[i].l,&tree[i].r),tree[i].val=-3;
else if(s[0]=='N') scanf("%d",&tree[i].l),tree[i].val=-4;
else scanf("%d",&tree[i].val),num[++k]=i;
}
dfs1(1);dfs2(1);
for(int i=1;i<=k;++i) printf("%d",vis[num[i]]^ans[1]);
}