【题解】LuoGu7073:表达式

255 篇文章 0 订阅
22 篇文章 0 订阅

原题传送门
我觉得,这道题目主要考察的还是把后缀表达式转成一棵树
然后遍历一遍树求出每个节点的值
然后暴力改动每个节点的值,往上跑,如果某一个时刻新算的值跟原来一样,那么就不用进行下去,否则继续
结果果然只T了一个点,然后我开了O2就过了

Code:

#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
struct Edge{
	int to, next;
}edge[maxn << 1];
int num, head[maxn], n, m, stk[maxn], top, val[maxn], sum[maxn], calc[maxn], flag, ans[maxn], tag[maxn], fa[maxn], rt;
char s[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void addedge(int x, int y){
	edge[++num] = (Edge){y, head[x]}, head[x] = num;
}

void build(int u){
	if (val[u] < 2) calc[u] = val[u];
	else if (val[u] == 2) calc[u] = 0;
	else calc[u] = 1;
	for (int i = head[u]; i; i = edge[i].next){
		int v = edge[i].to;
		fa[v] = u;
		build(v);
		if (val[u] == 2) calc[u] |= calc[v];
		else calc[u] &= calc[v];
	}
	calc[u] ^= tag[u];
}

void dfs(int u){
	if (sum[u] == calc[u]){
		flag = 1; return;
	}
	if (u == rt) return;
	int v = fa[u], i = head[v];
	while (edge[i].to == u) i = edge[i].next;
	int w = edge[i].to;
	if (val[v] == 2) sum[v] = sum[u] | calc[w];
	else sum[v] = sum[u] & calc[w];
	sum[v] ^= tag[v];
	dfs(v);
}

int main(){
	scanf("%s", s + 1);
	m = 1e6;
	while (!isdigit(s[1])){
		char c = s[1];
		if (c == 'x'){
			int x = 0;
			for (int i = 2; i <= strlen(s + 1); ++i) x = (x << 1) + (x << 3) + (s[i] ^ 48);
			stk[++top] = x;
		} else
		if (c == '|' || c == '&'){
			--m;
			val[m] = c == '|' ? 2 : 3;
			addedge(m, stk[top--]), addedge(m, stk[top--]), stk[++top] = m;
		} else
		if (c == '!') tag[stk[top]] ^= 1;
		scanf("%s", s + 1);
	}
	for (int i = 1; i <= strlen(s + 1); ++i) n = (n << 1) + (n << 3) + (s[i] ^ 48);
	rt = stk[top];
	for (int i = 1; i <= n; ++i) val[i] = read();
	build(rt);
	for (int i = 1; i <= n; ++i){
		sum[i] = tag[i] ^ val[i] ^ 1, flag = 0;
		dfs(i);
		if (flag) ans[i] = calc[rt];
		else ans[i] = calc[rt] ^ 1;
	}
	int Q = read();
	while (Q--) printf("%d\n", ans[read()]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值