H wcy的表达式
吴楚月的表达式
https://ac.nowcoder.com/acm/contest/9984/H
H题 wcy的表达式
解题思路
- 利用链式前向星构造树形结构
- 深度优先遍历该树,每遍历到一个节点,计算根节点到当前节点路径上的公式值,并纳入res[i],i为当前节点编号。
- 计算当前公式,可以始终维持一个数栈和操作栈,每次遇到栈顶操作符的优先级 >= 当前操作符优先级 时,将数栈和操作栈弹出计算公式,并将所得值放回数栈中。
- 例如
当前操作是+ 栈顶操作符* 满足条件,弹出数栈中两个值,操作符栈一个值,并计算
,15放回数栈中,并将+入操作符栈,6入数栈。 反之,
栈顶操作符+优先级 < 优先级,直接将压入操作栈,6压入数栈。
- 计算到该节点,直接计算目前保存在数栈和操作栈中的公式即可。操作栈中的运算符的优先级一定是 升序排列的,因为一旦出现逆序在第2步中就已经消除了。
- 除法都转换成乘法,所得数对MOD=1e9+7取余,所以数x的逆元就是
, 式
利用链式前向星构造树结构
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; }