解题思路
小知识:
后缀表达式求值,显然用栈。
建议使用手写栈,因为它很好写,常数还低 (至少CCF不会给你开O2)
这道题目最终让我们求的是某一个变量改变会不会对最终的值造成影响。
我们不妨设立 f f f数组,用 f i f_i fi表示第ii个数或运算的改变会直接影响到哪一个运算的结果。特别的,若 f i = 0 f_i=0 fi=0,则表示第ii个数或运算对其他结果都没有影响。
- 当运算为KaTeX parse error: Expected 'EOF', got '&' at position 2: x&̲y时:
- x为0时,y无法造成任何影响;
- y为0时,x无法造成任何影响。
- 当运算为 x ∣ y x|y x∣y时:
- x为1时,y无法造成任何影响;
- y为1时,x无法造成任何影响。
- 当运算为 x ! y x!y x!y时:x一定会造成影响。
那么修改一个变量,只要从它往上走,看最终能不能影响最后一个运算的结果即可。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct c{
int cnt,pl;
}lyx[1005000],k,z;//值(cnt)和位置(pl)
int j,y,n,m,ans,top,l,s[1005000],e[1005000],x[1005000],f[1005000],a[1005000];
/*
e表示每个运算:
若e[i]>0则e[i]就是题目中的 X [e[i]]
若e[i]=-1则表示&运算
若e[i]=-2则表示|运算
若e[i]=-3则表示!运算
l是e的长度
x[i]表示x[i]在e中的位置
f意义同上
*/
char ss[3030];
int main(){
while(1)
{
cin>>ss;
if(ss[0]>='0'&&ss[0]<='9')break;
l++;
if(ss[0]=='x')
{
sscanf(ss+1,"%d",&e[l]);
x[e[l]]=l;
}
if(ss[0]=='!')e[l]=-1;
if(ss[0]=='&')e[l]=-2;
if(ss[0]=='|')e[l]=-3;
}
sscanf(ss,"%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=l;i++)//求值并且给f赋值
{
if(e[i]>=0)
{
lyx[++top].cnt=a[e[i]];
lyx[top].pl=i;
}
if(e[i]==-1)
{
k=lyx[top];
lyx[top].cnt=!k.cnt;
lyx[top].pl=i;
f[k.pl]=i;
}
if(e[i]==-2)
{
k=lyx[top];
top--;
z=lyx[top];
lyx[top].pl=i;
lyx[top].cnt=k.cnt&z.cnt;
if(k.cnt==1) f[z.pl]=i;
if(z.cnt==1) f[k.pl]=i;
}
if(e[i]==-3)
{
k=lyx[top];
top--;
z=lyx[top];
lyx[top].pl=i;
lyx[top].cnt=k.cnt|z.cnt;
if(k.cnt==0) f[z.pl]=i;
if(z.cnt==0) f[k.pl]=i;
}
}
ans=lyx[top].cnt;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&y);
for(j=x[y];f[j];j=f[j]); //一路找到它最终会改变哪个值
if(j==l) //最后一个运算是l,那么当它会改变l时将原答案取反
printf("%d\n",!ans);
else printf("%d\n",ans);
}
}