树形dp——cf1010D

一个点的改变如果对根节点的值不会造成任何影响,那么这个点的所有子节点的改变也不会对根节点造成影响

因为每次只改一个叶子节点,也就是一条到根的路径,可以先预处理出初始情况下的每个结点的值

分别讨论根节点是and,or,xor,not时,1|2 个结点取值 的 各种情况(也就那么几种)

比如x是and,x有两个儿子u,v,

u=1,v=1时改变任意一个都会有影响

u=0,v=1时改变u会有影响

u=1,v=0时改变v会有影响

依次类推其他操作

/*
给定一棵逻辑运算的树,非叶子结点有and,or,xor,not四种操作
每个叶子结点都是一个输入
问每个叶子结点求反后可以得到的结果 
先一次dfs求出每个结点的值 
and:1  or:2  xor:3  not:4 
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define maxn 1000006
vector<int>G[maxn];
int n,a[maxn],op[maxn],flag[maxn];

void dfs1(int u){
    if(op[u]==0)return;
    for(int i=0;i<G[u].size();i++)
        dfs1(G[u][i]);
        
    if(op[u]==1)
        a[u]=a[G[u][0]] & a[G[u][1]];
    if(op[u]==2)
        a[u]=a[G[u][0]] | a[G[u][1]];
    if(op[u]==3)
        a[u]=a[G[u][0]] ^ a[G[u][1]];
    if(op[u]==4)
        a[u]=!a[G[u][0]];
} 
//flag[i]=1表示结点i的改变会改变根节点 
void dfs2(int u,int f){
    if(op[u]==0)return;
    if(f==0){//下面任意一个结点改变都没影响了 
        for(int i=0;i<G[u].size();i++){
            flag[G[u][i]]=0;
            dfs2(G[u][i],0);
        } 
        return;
    }

    int x,y;
    if(op[u]==1){//and
        x=G[u][0],y=G[u][1];
        if(a[x] && a[y]){
            flag[x]=flag[y]=1;
            dfs2(x,1);dfs2(y,1);
        }
        else if(a[x] && !a[y]){
            flag[y]=1;
            dfs2(x,0);dfs2(y,1);
        }
        else if(!a[x] && a[y]){
            flag[x]=1;
            dfs2(x,1);dfs2(y,0);
        }
        else dfs2(x,0),dfs2(y,0);
    } 
    if(op[u]==2){
        x=G[u][0],y=G[u][1];
        if(!a[x] && !a[y]){
            flag[x]=flag[y]=1;
            dfs2(x,1);dfs2(y,1);
        }
        else if(a[x] && !a[y]){
            flag[x]=1;
            dfs2(x,1);dfs2(y,0);
        }
        else if(!a[x] && a[y]){
            flag[y]=1;
            dfs2(x,0);dfs2(y,1);
        }
        else dfs2(x,0),dfs2(y,0);
    }
    if(op[u]==3){
        x=G[u][0],y=G[u][1];
        flag[x]=flag[y]=1;
        dfs2(x,1);dfs2(y,1);
    }
    if(op[u]==4){ 
        flag[G[u][0]]=1;
        dfs2(G[u][0],1); 
    } 
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        char s[5];
        int aa,b;
        scanf("%s",s);
        if(s[0]=='A'){
            scanf("%d%d",&aa,&b);
            G[i].push_back(aa);
            G[i].push_back(b);
            op[i]=1;
        }
        if(s[0]=='O'){
            scanf("%d%d",&aa,&b);
            G[i].push_back(aa);
            G[i].push_back(b);
            op[i]=2;
        }
        if(s[0]=='I')
            scanf("%d",&a[i]); 
        if(s[0]=='X'){
            scanf("%d%d",&aa,&b);
            G[i].push_back(aa);
            G[i].push_back(b);
            op[i]=3;
        }
        if(s[0]=='N'){
            scanf("%d",&aa);
            G[i].push_back(aa);
            op[i]=4;
        }
    }
    dfs1(1);//第一次dfs求出每个结点的初始值 
    int ans=a[1];
    dfs2(1,1);
    
    for(int i=1;i<=n;i++)
        if(op[i]==0){
            if(flag[i])cout<<!ans;
            else cout<<ans;
        }
}

 

posted on 2019-05-31 16:08  zsben  阅读(196)  评论(0编辑  收藏  举报

导航