题意:
给出一颗逻辑树,求分别反转每一个输入端的值后,输出端的值。
分析:
额,不得不说这次Div1前面几题真的水。。。打得好累。。。(以前都是悠闲地切题的,这次题水了,为了不掉rating就得疯狂地做。。。)
其实很简单,可以在每个位置维护一个值 dpi d p i 表示 i i 点值更改后能否影响到根。
转移的条件是,当其父亲值为1,且当前位置的值反转后,会影响父亲的值,那么当前位置dp值就为1,否则就为0
随便写写就出来了。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1000010
using namespace std;
int n,k,m,x;
int dp[MAXN];
char s[10];
vector<int> a[MAXN];
int fa[MAXN],bro[MAXN],val[MAXN],re[MAXN];
int ans[MAXN];
void dfs(int x){
for(int i=0;i<a[x].size();i++)
dfs(a[x][i]);
if(re[x]<2){
val[x]=re[x];
return ;
}
if(re[x]==2)
val[x]=val[a[x][0]]^1;
if(re[x]==3)
val[x]=val[a[x][0]]&val[a[x][1]];
if(re[x]==4)
val[x]=val[a[x][0]]|val[a[x][1]];
if(re[x]==5)
val[x]=val[a[x][0]]^val[a[x][1]];
return ;
}
bool check(int x){
if(x==1)
return 1;
if(dp[fa[x]]==0)
return 0;
int r=re[fa[x]];
if(r==2)
return 1;
int b=bro[x];
if(r==3)
return (val[fa[x]]!=((val[x]^1)&val[b]));
if(r==4)
return (val[fa[x]]!=((val[x]^1)|val[b]));
if(r==5)
return (val[fa[x]]!=((val[x]^1)^val[b]));
return 1;
}
void ddp(int x){
if(check(x))
dp[x]=1;
for(int i=0;i<a[x].size();i++)
ddp(a[x][i]);
}
int main(){
SF("%d",&n);
for(int i=1;i<=n;i++){
SF("%s",s);
int y;
if(s[0]=='N'){
re[i]=2;
SF("%d",&x);
a[i].push_back(x);
fa[x]=i;
}
else if(s[0]=='A'){
re[i]=3;
SF("%d%d",&x,&y);
a[i].push_back(x);
bro[x]=y;
a[i].push_back(y);
bro[y]=x;
fa[x]=i;
fa[y]=i;
}
else if(s[0]=='O'){
re[i]=4;
SF("%d%d",&x,&y);
a[i].push_back(x);
bro[x]=y;
a[i].push_back(y);
bro[y]=x;
fa[x]=i;
fa[y]=i;
}
else if(s[0]=='X'){
re[i]=5;
SF("%d%d",&x,&y);
a[i].push_back(x);
bro[x]=y;
a[i].push_back(y);
bro[y]=x;
fa[x]=i;
fa[y]=i;
}
else if(s[0]=='I'){
SF("%d",&x);
re[i]=x;
}
}
dfs(1);
dp[1]=1;
ddp(1);
for(int i=1;i<=n;i++)
if(re[i]<2)
PF("%d",dp[i]^val[1]);
}