函数调用:个人非常喜欢的一道拓扑题。
转化
这题一共有三种操作,不太好搞。而第一个函数看起来就比较可做,第三个函数显然就是让你拓扑转移,于是我们考虑第二个操作怎么处理。
当我们进行一个操作一后,假设当前节点的增量为 \(ad\)。此时如果再进行一次操作二,全局乘上 \(mul\),那么该节点最终的增量为 \(ad\times mul\)。根据乘法的定义,我们可以把这个增量转化为对该节点进行 \(mul\) 次操作一。
这就启发了我们考虑每个操作一会被执行多少次,显然是这个操作后面的操作的后缀积。
于是这题最关键的一步转化就做完了。
拓扑
因为操作三是要依次执行操作,也就是说它的子操作执行时,乘上的操作次数可能不相同。
因此,我们可以先预处理出每个操作完成之后会给全局乘上什么数,以便后面的计算。这个过程可以倒着拓扑一遍。
接下来就要转移函数执行次数了,我们定义 \(dp_i\) 表示该操作要被执行的次数。
显然,我们可以倒着枚举执行的操作,维护该操作内部的后缀积 \(nmul\),进行如下转移:
这就保证了前面的操作一定会算上后面函数的乘积了。
那么该如何初始化呢?同样是倒序枚举它给定的操作,维护一个后缀积,处理到某个操作的初始值时,其初始值就是当前的后缀积。
最后统计答案是容易的,因为只剩下操作一了,只要我们依次累计上答案即可。注意原来的值要乘上所有操作的全局积。
时间复杂度 \(O(m)\)。
实现
这题码量较大,再次梳理一遍代码过程:
- 倒着拓扑一遍,计算出每个函数操作之后给全局乘了多少。
- 倒着操作所有函数调用,实时维护一个后缀乘积,然后给各函数打标记。
- 顺着拓扑一遍,对于第三种函数,我们倒着枚举它的出边,然后进行转移,转移之后乘上对应节点的全局乘贡献。
代码
以上三个步骤在代码中被拆分成了三个函数来实现。
注意所有时候都要取模。
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
const ll mod=998244353;
int n,m,rd[100005],frd[100005],q,opf[100005];
ll a[100005],mul[100005],dp[100005],allmul,ad[100005];
struct node{int tp,p;ll v;
}f[100005];
vector<int>g[100005],fg[100005];
void topo1()
{queue<int>q;for(int i=1;i<=m;i++){if(frd[i]==0)q.push(i);if(f[i].tp==2)mul[i]=f[i].v;else mul[i]=1;}while(!q.empty()){int u=q.front();q.pop();for(auto v:fg[u]){mul[v]=(mul[v]*mul[u])%mod;frd[v]--;if(frd[v]==0)q.push(v);}}
}
void init()
{ll nmul=1;for(int i=q;i>=1;i--){dp[opf[i]]=(dp[opf[i]]+nmul)%mod;nmul=(nmul*mul[opf[i]])%mod;}allmul=nmul;
}
void topo2()
{queue<int>q;for(int i=1;i<=m;i++)if(rd[i]==0)q.push(i);ll nmul=1;while(!q.empty()){int u=q.front();q.pop();nmul=1;for(int i=g[u].size()-1;i>=0;i--){int v=g[u][i];dp[v]=(dp[v]+dp[u]*nmul%mod)%mod;nmul=(nmul*mul[v])%mod;rd[v]--;if(rd[v]==0)q.push(v);}}
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;for(int i=1;i<=n;i++)cin>>a[i];cin>>m;for(int i=1;i<=m;i++){int tp,p,v;cin>>tp;if(tp==1){cin>>p>>v;f[i]={1,p,v};}else if(tp==2){cin>>v;f[i]={2,0,v};}else{cin>>p;for(int j=1;j<=p;j++){int to;cin>>to;g[i].push_back(to);rd[to]++;fg[to].push_back(i);frd[i]++;}f[i]={3,p,0};}}cin>>q;for(int i=1;i<=q;i++)cin>>opf[i];topo1();init();topo2();for(int i=1;i<=m;i++)if(f[i].tp==1)ad[f[i].p]=(ad[f[i].p]+dp[i]*f[i].v%mod)%mod;for(int i=1;i<=n;i++)cout<<(allmul*a[i]%mod+ad[i])%mod<<" ";return 0;
}