zoukankan      html  css  js  c++  java
  • 2021牛客寒假算法基础集训营4 H. 吴楚月的表达式

    链接:https://ac.nowcoder.com/acm/contest/9984/H
    来源:牛客网

    题目描述

    众所周知,吴楚月在数据结构课的大作业环节选择了表达式求值。

    他觉得实现一个线性的表达式求值太无聊了,于是他把问题丢到了一棵树上。

    形式化地讲,这棵树有 n 个节点,1 号点为根,每个节点上都有一个权值 vivi ,代表参与运算的值。每条边都有一个 opiopi ,代表运算符。

    于是树上一条路径变成了 v−op−v−⋯−v−op−vv−op−v−⋯−v−op−v 的形式,对应一个表达式。

    吴楚月希望你对树上每一个节点 u ,计算出根到 u 的简单路径所对应的表达式的值。

    由于计算结果可能很大,所以你需要对 1e9+7 取模 。

    注:表达式优先级即正常的加减乘除的优先级,从左往右,乘除优先级高于加减。

    输入描述:

    第一行给出一个整数 n 表示节点个数。
    
    第二行 n 个正整数,第 i 个数表示 i 号节点的权值 vivi 。
    
    第三行 n-1 个正整数,第 i 个数 faifai 表示 i+1 号节点的父亲。
    
    第四行一个长度为 n-1 的字符串, 第 i 个字符表示 i+1 号节点与它父亲之间连边对应的运算符。
    
    其中 1≤n≤1e51≤n≤1e5,1≤vi≤1e91≤vi≤1e9,1≤fai≤i1≤fai≤i,opi∈{+,−,∗,/}opi∈{+,−,∗,/}。
    

    输出描述:

    一行输出 n 个数字,其中第 i 个数字表示根到 i 号节点的路径所对应的表达式的值。
    

    示例1

    输入

    复制

    3
    3 4 2
    1 1
    /*
    

    输出

    复制

    3 750000006 6
    

    比赛的时候看过的人不多以为要用到逆波兰表达式求值之类的来着,结束后突然发现并没有括号之类的东西Q^Q

    爬了

    题解写的挺好:

    作者:九峰
    链接:https://ac.nowcoder.com/discuss/596871?type=101&order=0&pos=1&page=1&channel=-1&source_id=1
    来源:牛客网

    一个非空表达式前缀可以表示成 a+ba+b 的形式。

    如果后面接了一个 +x+x ,则变成 (a+b)+x(a+b)+x ;

    如果后面接了一个 −x−x ,则变成 (a+b)+(−x)(a+b)+(−x) ;

    如果后面接了一个 ∗x∗x ,则变成 a+b∗xa+b∗x ;

    如果后面接了一个 /x/x ,则变成 a+b/xa+b/x 。

    最后还是可以表示成 a+ba+b 的形式。

    因此只需要遍历整棵树维护每个节点对应的 a+ba+b 即可。

    坑点是减法的时候要加上一个模数防止出现负数,以及除法取模要用到乘法逆元。

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <stack>
    #define mod 1000000007
    #define maxn 100005
    using namespace std;
    int n, val[maxn], head[maxn], ver[2 * maxn], Next[2 * maxn], tot = 0;
    string s;
    long long a[maxn], b[maxn];
    long long ans[maxn];
    void add(int x, int y)
    {
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    long long fpow(long long a, long long b)
    {
    	long long ans = 1;
    	for(; b; b >>= 1)
    	{
    		if(b & 1) ans = ans * a % mod;
    		a = a * a % mod;
    	}
    	return ans;
    }
    long long inv(long long x)
    {
    	return fpow(x, mod - 2);
    }
    void dfs(int x, int pre)
    {
    	for(int i = head[x]; i; i = Next[i])
    	{
    		int y = ver[i];
    		char op = s[y - 2];
    		if(y == pre) continue;
    		if(op == '+')
    		{
    			a[y] = (a[x] + b[x]) % mod, b[y] = val[y]; 
    		}
    		else if(op == '-')
    		{
    			a[y] = (a[x] + b[x]) % mod, b[y] = (-val[y] + mod) % mod; 
    		}
    		else if(op == '*')
    		{
    			a[y] = a[x], b[y] = b[x] * val[y] % mod;
    		}
    		else
    		{
    			a[y] = a[x], b[y] = b[x] * inv(val[y]) % mod;
    		}
    		dfs(y, x);
    	}
    	ans[x] = (a[x] + b[x]) % mod;
    }
    int main()
    {
    	freopen("data.txt", "r", stdin);
    	cin >> n;
    	for(int i = 1; i <= n; i++) cin >> val[i];
    	for(int i = 1; i <= n - 1; i++)
    	{
    		int fa;
    		cin >> fa;
    		add(fa, i + 1);
    		add(i + 1, fa);
    	}
    	cin >> s;
    	a[1] = 0, b[1] = val[1];
    	dfs(1, 0);
    	for(int i = 1; i <= n; i++)
    	{
    		cout << ans[i] << ' ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    AC自动机学习笔记(模板)
    codeforces1328E
    Codeforces 1288E- Messenger Simulator (树状数组)
    线性基小记
    HDU3949
    矩阵快速幂小记
    5E
    5D
    5C
    5B
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14417909.html
Copyright © 2011-2022 走看看