CSP-S T3 函数调用
事先声明,考试时由于本人太菜,T1写了两个小时还tm没判12.31挂了所以只是口胡了个拓扑排序,直接打了40分,考完自闭了很久之后才码出来
首先我们发现由于不会递归,所以把所有操作连起来会形成一张DAG,DAG上并没有什么很好的数据结构可以维护,所以可以考虑分别考虑乘法和加法的影响,可以发现,最终值是初始值乘以一堆值再加上一堆值
又因为乘法显然会对加法产生影响所以可以考虑,每个加法到最后都会加几次
可以发现每个加法最后加几次,等价于在这个加法之后,全局乘的数值的积,于是我们可以考虑倒着处理这个函数数列
每次加法的时候就加上标记,(前面乘的积),乘法就更新全局积,如果是递归,就先给它下辖(即最终会被调用的乘法或者加法)的所有加法加上标记(打在它本身上面,最终拓扑排序下传),然后再用下面的乘法更新全局积
最后打完标记最后拓扑排序下传一下就行.具体地依然从后往前处理,注意要更新一下最终加法的次数(类似于线段树合并,处理右儿子时要考虑左儿子的贡献),具体看代码吧
其实也不是很难,还是我太菜了
/*call*/ #include<bits/stdc++.h> using namespace std; int read(){ char c = getchar(); int x = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar(); return x; } const int maxn = 1e6 + 10; struct Edge{ int nxt,point; }edge[maxn<<1]; int a[maxn]; int head[maxn],tot; int deg[maxn]; void add_edge(int x,int y){ edge[++tot].nxt = head[x]; edge[tot].point = y; head[x] = tot; deg[y]++; } struct Func{ int op; int p,v; }f[maxn]; int seq[maxn]; int C = 1; int tag[maxn]; #define mod 998244353 int mul[maxn]; void add(int &x,int y){ x += y - mod; x += (x >> 31) & mod; } void sol(int x){ if(f[x].op == 1){ add(tag[f[x].p],1ll * C * f[x].v % mod) ; return; } else if(f[x].op == 2){ C = 1ll * C * f[x].v % mod; } else{ for(int i = head[x]; i; i = edge[i].nxt){ sol(edge[i].point); } } } void dfs(int x){ if(~mul[x]) return; mul[x] = 1; if(f[x].op == 1) return; if(f[x].op == 2){ mul[x] = f[x].v; return; } for(int i = head[x]; i ; i = edge[i].nxt) dfs(edge[i].point),mul[x] = 1ll * mul[x] * mul[edge[i].point] % mod; } int q[maxn]; int main(){ int n = read(); for(int i = 1; i <= n; ++i) a[i] = read(); int m = read(); for(int i = 1; i <= m; ++i){ int op = read(); f[i].op = op; if(op == 1){ f[i].p = read(),f[i].v = read(); } else if(op == 2){ f[i].v = read(); } else{ int s = read(); for(int j = 1; j <= s; ++j){ int x = read(); add_edge(i,x); } } } memset(mul,-1,sizeof(mul)); int t = read(); for(int i = 1; i <= t; ++i) seq[i] = read(); for(int i = 1; i <= m; ++i) dfs(i); for(int x = t; x; --x){ if(f[seq[x]].op == 1) add(tag[seq[x]],C); if(f[seq[x]].op == 2) C = 1ll * C * f[seq[x]].v % mod; if(f[seq[x]].op == 3){ add(tag[seq[x]],C); C = 1ll * C * mul[seq[x]] % mod; } } for(int i = 1; i <= n; ++i) a[i] = 1ll * a[i] * C % mod; int l = 1,r = 0; for(int i = 1; i <= m; ++i) if(!deg[i]) q[++r] = i; while(l <= r){ int x = q[l++]; if(f[x].op == 1){ add(a[f[x].p],1ll * tag[x] * f[x].v % mod); continue; } if(f[x].op == 2) continue; int v = 1; for(int i = head[x]; i ; i = edge[i].nxt){ int y = edge[i].point; add(tag[y],1ll * tag[x] * v % mod); --deg[y];if(!deg[y]) q[++r] = y; v = 1ll * v * mul[y] % mod; } } for(int i = 1; i <= n; ++i) printf("%d%c",a[i]," \n"[i == n]); return 0; }