表达式 题解
零、写在前面
这道题是 ,但个人认为比第四题还要恶心
当时考场上这道题没写出来,现在发现这道题的算法和思想其实是 结论和模拟
一、思路
首先考虑最关键的询问:因为每个询问都要修改一个数,每次在线修改太过复杂,时间也会承受不了,所以我们考虑先把答案算出来,对于每个数判断它对答案的影响(因为答案只属于
大意就是判断一个变量对答案有没有影响,比如 1 | x = 1
和 0 & x = 0
中 1 & x
和 0 | x
中的 !x
中
大体方向考虑好以后,我们考虑程序的流程
首先输入了一行后缀表达式,我们要解出这道题目肯定要把这个表达式解析出来,这里我们考虑利用栈来建立 表达式树 以处理这个后缀表达式(不清楚 表达式树 的看 这里 或自行在百度、B站等网站上搜索)
然后我们对树上的每个变量都打上一个
- 与操作符
&
:对于&
来说,如果一棵子树结果是 ,就给另一棵子树打上标记 ,代表 另一棵子树的结果不会对答案造成影响,是个可有可无的东西(如果不是就打上标记 ) - 或操作符
|
:对于|
来说,如果一棵子树结果是 ,就给另一棵子树打上标记 ,代表 另一棵子树的结果不会对答案造成影响(如果不是就打上标记 ) - 非操作符
!
:对于!
来说,由于!
一定会对当前变量或表达式产生反转的结果,所以我们利用 德·摩根定律,下传标记让该节点及其子树全部反转(其实可以不用反转子树的)
最后我们先计算出该表达式原有的答案
如果是,就直接输出 ans
,如果不是,就输出 !ans
#include<bits/stdc++.h> using namespace std; int n,cnt,ans,Q; int val[1000009],tra[1000009],pl[1000009]; pair<int,int>tree[1000009]; string str; inline int take(int &p) { p++; int res=0; while(str[p]!=' ') res*=10,res+=str[p++]-48; p--; return res; } inline void work(stack<int>& res,int& now,int vv) { int t1,t2; t1=res.top(),res.pop(),t2=res.top(),res.pop(),res.push(++now); val[cnt]=vv,tree[cnt]=make_pair(t1,t2);//建立表达式树 return; } inline void expr() { cnt=n; stack<int>st; while(!st.empty()) st.pop();//用栈来建立表达式树 for(int i=0;i<str.size();i+=2) switch(str[i]) { case 'x': st.push(take(i));//处理以 i 为起点的数字并压入栈中 break; case '&': work(st,cnt,2);//按上文说的处理运算符 break; case '|': work(st,cnt,3);//同理 break; case '!': tra[st.top()]^=1;//把该结点的标记反转 break; } return; } inline int dfs(int u,int tp) { val[u]^=tp; if(u<=n) return val[u]; pair<int,int>res=make_pair(dfs(tree[u].first,tp^tra[tree[u].first]), dfs(tree[u].second,tp^tra[tree[u].second])); if(val[u]==2) { if(!res.first) pl[tree[u].second]=1; if(!res.second) pl[tree[u].first]=1;//同时打标记 return res.first&res.second; } else { if(res.first==1) pl[tree[u].second]=1; if(res.second==1) pl[tree[u].first]=1; return res.first|res.second; } } inline void push_down(int u) { if(u<=n) return; pl[tree[u].first]|=pl[u],pl[tree[u].second]|=pl[u]; push_down(tree[u].first),push_down(tree[u].second); return; } signed main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0);//cin,cout 优化 getline(cin,str); cin>>n; for(int i=1;i<=n;i++) cin>>val[i];//输入 expr();//建立表达式树 ans=dfs(cnt,tra[cnt]);//计算表达式的值 push_down(cnt);//标记从根节点开始下放 cin>>Q; while(Q--) { int u; cin>>u; if(pl[u]) cout<<ans;//如果对答案没影响就直接输出 ans else cout<<!ans;//不然就输出 !ans cout<<endl;//记得换行 } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效