loj3381. 「CSP-S 2020」函数调用
诈骗题。看起来很像数据结构,事实上是个图论。
题目明确说明调用关系是一个 DAG,考虑拓扑排序。
不难发现乘法的本质上是将加法操作重复了若干次,于是我们可以考虑把所有操作都转化为加法操作。
每个加法的贡献次数是他后面所有乘法操作的乘积,我们可以直接在 DAG 上面 dp 出每一个 3 类型函数内部执行到第 \(i\) 个调用的时候的乘法操作后缀积,然后再拓扑排序求出每个加法操作在这个序列里面会被执行多少次,然后直接把贡献加到变量上面就好了。
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#define int long long
const int mod=998244353;
struct function
{
int opt,pos,val;
vector<int> son;
}fun[1000001];
int n,m,p,a[1000001],d[1000001],sum[1000001];
vector<int> f[1000001],v[1000001];
bool vis[1000001];
inline int read()
{
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x;
}
void print(int x)
{
if(x>=10)
print(x/10);
putchar(x%10+'0');
}
inline void dfs(int k)
{
vis[k]=1;
if(fun[k].opt==1)
{
f[k].push_back(1);
f[k].push_back(1);
return;
}
if(fun[k].opt==2)
{
f[k].push_back(fun[k].val);
f[k].push_back(1);
return;
}
for(auto i:fun[k].son)
{
if(!vis[i])
dfs(i);
f[k].push_back(f[i][0]);
}
for(register int i=f[k].size()-2;~i;--i)
f[k][i]=f[k][i]*f[k][i+1]%mod;
f[k].push_back(1);
}
inline void topo()
{
sum[m]=1;
queue<int> q;
for(register int i=1;i<=m;++i)
if(!d[i])
q.push(i);
while(!q.empty())
{
int k=q.front();
q.pop();
int j=0;
for(auto i:fun[k].son)
{
++j;
if(!--d[i])
q.push(i);
if(!vis[k])
continue;
sum[i]=(sum[i]+sum[k]*f[k][j]%mod)%mod;
}
}
}
signed main()
{
n=read();
for(register int i=1;i<=n;++i)
a[i]=read();
m=read();
for(register int i=1;i<=m;++i)
{
fun[i].opt=read();
if(fun[i].opt==1)
fun[i].pos=read(),fun[i].val=read();
if(fun[i].opt==2)
fun[i].val=read();
if(fun[i].opt==3)
{
p=read();
while(p--)
{
fun[i].son.push_back(read());
++d[fun[i].son.back()];
}
}
}
p=read();
++m;
for(register int i=1;i<=p;++i)
{
fun[m].son.push_back(read());
++d[fun[m].son.back()];
}
dfs(m);
topo();
for(register int i=1;i<=n;++i)
a[i]=(a[i]*f[m][0])%mod;
for(register int i=1;i<=m;++i)
if(fun[i].opt==1)
a[fun[i].pos]=(a[fun[i].pos]+sum[i]*fun[i].val%mod)%mod;
for(register int i=1;i<=n;++i)
{
print(a[i]);
putchar(' ');
}
puts("");
return 0;
}