标签:树形dp 描述 algo 运算符 put min 逻辑运算 ret cst
时间限制: 3.0 秒
空间限制: 512 MB
相关文件: 题目目录
有一棵树,叫逻辑树。
这个树有根,有 2N−1 个节点,其中 N 个叶子,每个非叶节点恰好有两个孩子。
每个叶子上有一个 01 变量,它的取值可能为 True 或 False。每个非叶节点上有一个逻辑运算符,这个运算可能为 AND 或者 OR。
一个非叶节点的取值定义为它两个儿子的取值,作这个节点上的运算得到的结果。
有一个黑恶势力想知道这个树的根节点的取值,他准备了一个长度为 N 的询问序列 {Pi},每个叶子在这个序列中恰好出现一次。
黑恶势力会依次询问这些叶子的值,但是,如果他发现某一次询问是不必要的,那么他会跳过这个无意义的询问(为了帮助理解,考虑 x AND y 在我们知道 x 为 False 之后,不必知道 y 的值就可推算 x AND y 的值)。
当然,邪恶总是能战胜正义,黑恶势力总能达到他的目的。但是我们可以拖慢他的节奏,你现在可以安排每个叶子的权值,使得黑恶势力询问的次数尽可能多,在此基础上,我们希望这个树的根节点取值尽量为 True。
请你计算一组解,任何一种合法方案都是可以接受的。
从标准输入读入数据。
第一行一个整数 N,意义如题面所示。
接下来一行 N−1 个整数,第 i 个数代表节点 N+i 上的运算符,其中 0 表示 AND
,1 表示 OR
。
接下来 2N−2 行,每行两个整数u,v,描述一条u,v之间的边。
最后一行 N 个整数,表示黑恶势力的询问序列。
你可以认为 1∼N 是叶子,N+1∼2N−1 是非叶节点,且 N+1 是根,输入数据保证每个非叶节点有两个孩子。
输出到标准输出。
输出一个长度为 N 的 01串 S,其中 Si 表示第 i 个叶子的取值,0 为 False, 1 为 True.
显然这是一个特殊地树形DP
我们首先将树上每个节点的儿子都处理出来
然后从根节点跑第一遍DFS
然后我们就可以通过询问的次序,处理出这个点被查到的先后
当然为了尽可能不让黑帮老大猜到,我们会按位运算的种类分配
父亲的值知道,当且仅当在构造情况下两个儿子的值都知道
(我们针对位运算进行构造,与知道有0就是0,或知道有1就是1,要避免)
这时候知道父亲的时刻就是两个儿子中后知道值的那个的时刻
在顺序确定好后我们跑第二遍DFS
即可确定值
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rii register int i #define rij register int j using namespace std; int head[1000005],cnt,n; struct edge{ int cnt,bj,s[3],val,bh; }x[1000005]; struct ljb{ int to,nxt; }y[4000005]; inline void add(int from,int to) { cnt++; y[cnt].nxt=head[from]; y[cnt].to=to; head[from]=cnt; } void ycl(int wz,int fa) { for(rii=head[wz];i;i=y[i].nxt) { int to=y[i].to; if(to==fa) { continue; } x[wz].s[x[wz].cnt]=to; x[wz].cnt++; ycl(to,wz); } return; } void dfs(int wz) { if(wz<=n) { return; } dfs(x[wz].s[1]); dfs(x[wz].s[0]); if(x[x[wz].s[0]].bh>x[x[wz].s[1]].bh) { swap(x[wz].s[0],x[wz].s[1]); } x[wz].bh=x[x[wz].s[1]].bh; return; } void dfs2(int wz) { if(wz<=n) { return; } if(x[wz].bj==0) { if(x[wz].val==0) { x[x[wz].s[0]].val=1; x[x[wz].s[1]].val=0; } else { x[x[wz].s[0]].val=1; x[x[wz].s[1]].val=1; } } else { if(x[wz].bj!=0) { if(x[wz].val==0) { x[x[wz].s[0]].val=0; x[x[wz].s[1]].val=0; } else { x[x[wz].s[0]].val=0; x[x[wz].s[1]].val=1; } } } dfs2(x[wz].s[0]); dfs2(x[wz].s[1]); return; } int main() { scanf("%d",&n); for(rii=n+1;i<(n<<1);i++) { scanf("%d",&x[i].bj); } for(rii=1;i<=(n-1)<<1;i++) { int from,to; scanf("%d%d",&from,&to); add(from,to); add(to,from); } ycl(n+1,0); for(rii=1;i<=n;i++) { int from; scanf("%d",&from); x[from].bh=i; } dfs(n+1); x[n+1].val=1; dfs2(n+1); for(rii=1;i<=n;i++) { x[i].val?putchar(‘1‘):putchar(‘0‘); } return 0; }
标签:树形dp 描述 algo 运算符 put min 逻辑运算 ret cst
原文地址:https://www.cnblogs.com/ztz11/p/9902175.html