题目
推演

思路
1.建立结构体数组
2.每个数组元素有两参数
变量0/1数值
布尔变量,表示能否影响最后结果
能影响的,该元素数值变结果就变,
不影响的,结果是啥就是啥
3.先建立二叉树根节点root,完了往里加
倒序读取表达式各元素,组建二叉树
如果父的左右树都满,就上溯找到有缺的祖辈节点
变量,根据序号找到结构体数组中对应元素,得指针,入二叉树(父节点不变)
运算符,新建结构体指针,入二叉树(本节点变成父节点)
4.递归算运算符结果,先算左右,再根据运算符得自己
根据运算符并左值,判定右值是否能影响结果
根据运算符并右值,判定左值能否影响结果
5. !
对父有影响
&
左0,右对父无影响
右0,左对父无影响
|
左1,右对父无影响
右1,左对父无影响
6.子继承父,从上往下传递该节点是否对根的值有影响。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{
int id;//序号-
bool d,//该元素的逻辑值
k;//0表示对结果没影响
char c;//运算符
node *f,*l,*r;//父,左,右
node(){c='*';f=l=r=NULL;k=1;id=0;}//无参构造,默认是1,对结果有影响
node(char cx){f=l=r=NULL;k=1;c=cx,id=0;}//无参构造,默认是1,对结果有影响
void add(node *x){//添加子
if(!r)r=x,x->f=this;//先右
else if(!l)l=x,x->f=this;//后左
}
}d[N],//各序号对应结构体变量,对应指针是二叉树节点
root,//始终可以找到的根节点
*cur,//当前节点
*fa;//留待处理的父节点
string sx,line;//变量和运算符
stack<string> st;//用来倒序表达式,以生成二叉树
void view(node* x){//递归后序显示二叉树,
if(x->l)view(x->l);
if(x->id)cout<<'x'<<x->id<<"="<<x->d<<" ";
else cout<<x->c<<" ";
if(x->c!='!'&&x->r)view(x->r);
}
bool run(node* x){//推算表达式结果
if(x->id)return x->d;//递归出口,递归基,遇叶节点返值
bool k1,k2;//分别计算左右树
if(x->l)k1=run(x->l);
if(x->r&&x->c!='!')k2=run(x->r);
if(x->c=='!')return !k1;//非运算,只返回左树结果
else if(x->c=='&'){//与运算,
if(!k1)x->r->k=0; //左树0,则右树不能影响父
if(!k2)x->l->k=0;//右树0,则左树无影响
return k1&&k2;//返回左右树的与结果
}else if(x->c=='|'){//非运算
if(k1)x->r->k=0; //左树1,则右树不能影响父
if(k2)x->l->k=0;//右树1,则左树无影响
return k1||k2;//返回左右树的或结果
}
}
void kdown(node *x){//如果父对根的结果无影响,则子树也同样
if(x->l){//有左树
if(!x->k)x->l->k=0;//左树继承父对根无影响
kdown(x->l);//递归
}
if(x->r&&x->c!='!'){
if(!x->k)x->r->k=0;//右树继承无影响
kdown(x->r);
}
}
int n,//变量数
x,//
ans,//表达式最初结果
q; //询问次数
int main(){
//freopen("data.cpp","r",stdin);
getline(cin,line);//以换行符为分隔符输入一行字符串
istringstream cinx(line);//把字符串 line 转换成字符串流(istringstream 类型)
while(cinx>>sx)st.push(sx);//插入栈,完成倒序
fa=&root;//父指向根
while(!st.empty()){//遍历算式
string s=st.top();st.pop();//倒序取得变量序号和运算符
while(fa->l&&fa->r)fa=fa->f;//向上找到左右儿子有缺的父节点
if(s[0]=='x'){//变量,是叶子节点,fa不变
int id=stoi(s.substr(1,s.length()));//x后的数字是序号
d[id].id=id;//仅备查看
cur=&d[id];//指针指向数组该序号位置
fa->add(cur);//接上二叉树,接入当前父节点
}else{
cur=new node{s[0]};//创建运算符节点
if(s[0]=='!'){//一元操作符
node *kong=new node{};//空节点
cur->add(kong);//补成该运算符右树
}
fa->add(cur);//接入二叉树
fa=cur;//该运算符变成父节点
}
}
//view(root.r);cout<<endl;
cin>>n;//变量数
for(int i=1;i<=n;i++){
cin>>x;d[i].d=x;//确定各变量的初始值
}
//view(root.r);cout<<endl;
ans=run(root.r);//推算表达式结果
kdown(root.r);//如果某父节点对根结果无影响,则往下都无影响
//cout<<ans<<endl;
//view2(root.r);cout<<endl;
cin>>q;
for(int i=1;i<=q;i++){//询次数
cin>>x;//修改变量序号
if(d[x].k)cout<<!ans<<endl;
else cout<<ans<<endl;
}
return 0;
}
小结
要花够足够的时间和精力



1367

被折叠的 条评论
为什么被折叠?



