题解 P7077 【函数调用(洛谷民间数据)】

· · 题解

upd on 2020.11.17:补充说明。

题目传送门。

不妨将题目看成:将所有数乘上 mult,再给某些数加上 add_i,其中 mult 是所有被调用的 type II 函数给所有数乘的 V_j 之积。

不难发现函数的调用关系是 DAG,建完图后可以一遍 dfs 求出 mul_i 表示第 i 个函数调用后会将所有数乘上 mul_i

现在只要求出 add_i 即可:

想一下,如果一个 type I 函数被调用之后,所有数又乘上了 mult,那么就相当于该函数产生了 mult 倍的贡献,这启发我们用数组 f_i 表示第 i 个函数对它所调用的单点加法产生了 f_i 倍的贡献。

可以先把每个函数在一开始调用时的产生的贡献求出,对于 type III 函数,不进行下传递归,最后再用拓扑排序更新真正的 f_i

一开始的贡献可以倒序处理所有函数调用:

为什么要倒序处理:一开始计算的贡献 f_i在调用该函数后所有数被乘了 f_i,因此需要倒序处理。

最后拓扑排序时,对于每个函数:

最后每个数输出 a_i\times mult+add_i 即可。

感觉可以通过差分做到线性时间区间修改,要是我就加强了(

时间,空间复杂度 O(n+m)。读入量较大,建议使用快读。

拿样例 1 举个例子:

不难求出 mul=\{1,2,2\}。此时 mult=1

调用的函数分别为 2,3,那么我们倒序处理调用:

首先是 3f_3\gets f_3+mult=1mult\gets mult\times mul_3=2

然后是 2mult\gets mult\times mul_2=4

此时 mult=4f=\{0,0,1\},度数 deg=\{1,1,0\}

接下来拓扑排序,因为 3 的入度为 0 所以首先被压入队列。

最后分别输出:

$a_2\times mult+add_2=2\times 4+0=8$; $a_3\times mult+add_3=3\times 4+0=12$。 --- 非考场代码: ```cpp #include <bits/stdc++.h> using namespace std; #define ll long long inline ll read(){ ll x=0,sign=0; char s=getchar(); while(s>'9'||s<'0')sign|=s=='-',s=getchar(); while(s<='9'&&s>='0')x=(x<<1)+(x<<3)+s-'0',s=getchar(); return sign?-x:x; } const int N=1e5+5; const int mod=998244353; int n,m,c,a[N],deg[N],func[N]; int tp[N],pos[N],val[N]; ll mu=1,mul[N],dp[N],add[N]; vector <int> e[N]; queue <int> q; bool vis[N]; void dfs(int id){ vis[id]=1,mul[id]=(tp[id]==2?val[id]:1); for(int it:e[id]){ if(!vis[it])dfs(it); mul[id]=mul[id]*mul[it]%mod; } } int main(){ n=read(); for(int i=1;i<=n;i++)a[i]=read(); m=read(); for(int i=1;i<=m;i++){ tp[i]=read(); if(tp[i]==1)pos[i]=read(),val[i]=read(); else if(tp[i]==2)val[i]=read(); else{ c=read(); while(c--){ int to=read(); e[i].push_back(to),deg[to]++; } } } c=read(); for(int i=1;i<=m;i++)if(!vis[i]&&!deg[i])dfs(i); for(int i=1;i<=c;i++)func[i]=read(); for(int i=c,f=func[i];i;i--,f=func[i]){ if(tp[f]==1)dp[f]=(dp[f]+mu); else if(tp[f]==2)mu=mu*val[f]%mod; else dp[f]=(dp[f]+mu),mu=mu*mul[f]%mod; } for(int i=1;i<=m;i++)if(!deg[i])q.push(i); while(!q.empty()){ int t=q.front(); q.pop(); if(tp[t]==1)add[pos[t]]=(add[pos[t]]+dp[t]*val[t])%mod; ll z=dp[t]; reverse(e[t].begin(),e[t].end()); for(int p:e[t]){ deg[p]--; if(!deg[p])q.push(p); dp[p]=(dp[p]+z)%mod,z=z*mul[p]%mod; } } for(int i=1;i<=n;i++)cout<<(a[i]*mu+add[i])%mod<<" "; return 0; } ```