P7077 [CSP-S2020] 函式呼叫
阿新 • • 發佈:2021-07-25
無
預處理出函式 \(i\) 乘上的係數 \(mul_i\),顯然函式之間的呼叫關係形成了一張拓撲圖。
不妨將整個程式視為一個型別 \(3\) 的函式,從其開始拓撲排序。記 \(k_i\) 表示位置 \(i\) 當前加上的數,\(f_i\) 表示函式 \(i\) 當前對其中加法函式的呼叫次數。
注意到一個加法函式產生的貢獻只取決於加數和呼叫次數,後者我們可以通過累加的方式來得到;一個
- 型別 \(1\)。此後再也不會呼叫它了,那麼它的貢獻可以算好了:\(k_{P_i}\gets k_{P_i}+V_i\times f_i\)。
- 型別 \(2\)。其貢獻在 \(mul\) 中,直接忽略。
- 型別 \(3\)
函式 \(i\) 呼叫了函式 \(j\):\(f_j\gets f_j+f_i,f_i\gets f_i\times mul_j\)。
注意沒出現過的函式要刪掉出邊以免影響拓撲排序。時間複雜度 \(O(n)\)。
code:
#include<bits/stdc++.h> using namespace std; #define N 100005 #define NN 1000005 #define Mod 998244353 #define For(i,x,y)for(i=x;i<=(y);i++) struct node { int next,to; }e[2000005]; bool vis[NN]; queue<int>que; int head[NN],p[NN],val[NN],t[NN],mul[NN],deg[NN],f[NN],a[N],k[N],g; int read() { int A; bool K; char C; C=A=K=0; while(C<'0'||C>'9')K|=C=='-',C=getchar(); while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar(); return(K?-A:A); } inline void add(int u,int v) { e[++g].to=v; e[g].next=head[u]; head[u]=g; } void dfs(int u) { if(vis[u])return; int v,i; vis[u]=1; if(t[u]==2)mul[u]=val[u]; else if(t[u]==3) { mul[u]=1; for(i=head[u];i;i=e[i].next) { v=e[i].to; dfs(v); mul[u]=1LL*mul[u]*mul[v]%Mod; } } else mul[u]=1; } int main() { // freopen("call.in","r",stdin); // freopen("call.out","w",stdout); int n,i,m,c,x,u,v,q; n=read(); For(i,1,n)a[i]=read(); m=read(); For(i,1,m) { t[i]=read(); if(t[i]==1)p[i]=read(),val[i]=read(); else if(t[i]==2)val[i]=read(); else { c=read(); while(c--) { x=read(); add(i,x); deg[x]++; } } } t[++m]=3; q=read(); while(q--) { x=read(); add(m,x); deg[x]++; } mul[m]=f[m]=1; dfs(m); For(u,1,m) if(!vis[u]) for(i=head[u];i;i=e[i].next)deg[e[i].to]--; que.push(m); while(!que.empty()) { u=que.front(); que.pop(); if(t[u]==1)k[p[u]]=(k[p[u]]+1LL*val[u]*f[u])%Mod; else if(t[u]==3) for(i=head[u];i;i=e[i].next) { v=e[i].to; deg[v]--; if(!deg[v])que.push(v); /*printf("%d %d\n",u,v);*/ f[v]=(f[v]+f[u])%Mod; f[u]=1LL*f[u]*mul[v]%Mod; } } For(i,1,n)printf("%d ",(1LL*a[i]*mul[m]+k[i])%Mod); return 0; }