H题 wcy的表达式
解题思路
- 利用链式前向星构造树形结构
- 深度优先遍历该树,每遍历到一个节点,计算根节点到当前节点路径上的公式值,并纳入res[i],i为当前节点编号。
- 计算当前公式,可以始终维持一个数栈和操作栈,每次遇到栈顶操作符的优先级 >= 当前操作符优先级 时,将数栈和操作栈弹出计算公式,并将所得值放回数栈中。
- 例如
当前操作是+ 栈顶操作符* 满足条件,弹出数栈中两个值,操作符栈一个值,并计算
,15放回数栈中,并将+入操作符栈,6入数栈。 反之,
栈顶操作符+优先级 < 优先级,直接将压入操作栈,6压入数栈。 - 计算到该节点,直接计算目前保存在数栈和操作栈中的公式即可。操作栈中的运算符的优先级一定是 升序排列的,因为一旦出现逆序在第2步中就已经消除了。
- 除法都转换成乘法,所得数对MOD=1e9+7取余,所以数x的逆元就是
, 式
利用链式前向星构造树结构
训练营一 C 红和蓝
int n,tot = 0;
int head[SIZE];
struct star{
int to, next;
char op;// 权值是 边操作
} edge[SIZE];
void addedge(int x, int y, char op) {
edge[++tot].to = y;
edge[tot].next = head[x];
edge[tot].op = op;
head[x] = tot;
}
实现代码
#include <bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
const int SIZE=1e5+10;
long long qsm(long long a, long long b) {
long long sum = 1, t = a;
while (b) {
if (b&1) sum = sum * t % MOD;
t = t * t % MOD;
b >>= 1;
}
return sum;
}
int n,tot = 0;
int head[SIZE];
struct star{
int to, next;
char op;// 权值是 边操作
} edge[SIZE];
void addedge(int x, int y, char op) {
edge[++tot].to = y;
edge[tot].next = head[x];
edge[tot].op = op;
head[x] = tot;
}
int data[SIZE];
char op[SIZE];
int fa[SIZE];
int res[SIZE];
int cmp(char x, char y) {
if ((x == '+' || x == '-') && ( y=='*' || y=='/' )) {
return -1; // 暂时不可以计算
} else if ((y == '+' || y == '-') && ( x=='*' || x=='/' )) {
return 1; // 可以计算
} else return 0; // 可以计算
}
long long ni(int x, int p) {
return qsm(x, p-2);
}
int doop(int x, int y, char op) {
//printf("%d %c %d \t", x, op, y);
if (op == '+') return ((long long)x+y)%MOD;
else if (op == '-') return ((long long)x-y+MOD)%MOD;
else if (op == '*') return ((long long)x*y)%MOD;
else if (op == '/') return ((long long)x*ni(y,MOD))%MOD;
return -1;
}
int compute(vector<char> opp, vector<int> number) {
int cur = -1;
while (!opp.empty()) {
char c = opp.back(); opp.pop_back();
int x = number.back(); number.pop_back();
int y = number.back(); number.pop_back();
cur = doop(y, x, c);
number.push_back(cur);
}
//if (number.empty()) cur = data[1];
if (opp.empty()) cur = number.back();
return cur;
}
void dfs1(int x, int fat, vector<char> opp, vector<int> number) {
while (!opp.empty() && cmp(op[ x ], opp.back() ) <= 0 ) {
char c = opp.back(); opp.pop_back();
int x = number.back(); number.pop_back();
int y = number.back(); number.pop_back();
int kl = doop(y, x, c);
number.push_back(kl);
}
number.push_back(data[x]);
if (x!=1) opp.push_back( op[x] );
res[x] = compute(opp, number);
// 深度优先遍历更新当前节点的值
for (int i=head[x]; i!=-1; i= edge[i].next) {
if (edge[i].to == fat) continue;
dfs1(edge[i].to, x, opp, number);
}
}
int main() {
memset(head, -1, sizeof(head));
scanf("%d", &n);
for (int i=1;i<=n;i++) scanf("%d", &data[i]);
for (int i=2;i<=n;i++) scanf("%d", &fa[i]);
scanf(" %s", op+2);
for (int i=2; i<=n; i++) {
addedge(fa[i], i, op[i]); // 添加父亲到当前节点的边
}
vector<char> op;
vector<int> number;
res[1] = data[1];
dfs1(1, 0, op, number);
for (int i=1;i<=n;i++) {
if (i==1) printf("%d", res[i]);
else printf(" %d", res[i]);
}
return 0;
}