有
n
n
n个元素,进行一些函数的操作。
功能可分为三类:
- 单点加;
- 全局乘;
- 依次执行若干次函数调用,保证不会出现递归(即不会直接或间接地调用本身)。
考虑给这些函数的调用关系建图,得到一个DAG。
若无操作1,则用拓扑排序计算出每个函数调用后给全局乘上的值。
考虑算上操作1,那么对于一个加法后的乘法,会给加法的贡献也乘上一个权值,那么可以倒着进行一次拓扑排序,算出每个加法被乘上之后的贡献。
代码#include#include #include #define int long long const int mod = 998244353; std::vector G1[100001], G2[100001]; int n, m; int a[100001], mul[100001], cnt[100001], pos[100001], add[100001], deg[100001]; void topsort1() { std::queue q; for (int i = 0; i <= m; i++) { deg[i] = G2[i].size(); if (!deg[i]) q.push(i); } while (q.size()) { int x = q.front(); q.pop(); for (int i = 0; i != G1[x].size(); i++) { int y = G1[x][i]; (mul[y] *= mul[x]) %= mod; deg[y]--; if (!deg[y]) q.push(y); } } } void topsort2() { std::queue q; for (int i = 0; i <= m; i++) { deg[i] = G1[i].size(); if (!deg[i]) q.push(i); } while (q.size()) { int x = q.front(); q.pop(); int now = 1; for (int i = G2[x].size() - 1; i >= 0; i--) { int y = G2[x][i]; (cnt[y] += now * cnt[x] % mod) %= mod;//具体地,通过计算每个函数操作次数来算贡献 (now *= mul[y]) %= mod; deg[y]--; if (!deg[y]) q.push(y); } } } signed main() { scanf("%lld", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); scanf("%lld", &m); mul[0] = 1; for (int i = 1; i <= m; i++) { mul[i] = 1; int typ; scanf("%lld", &typ); if (typ == 1) { scanf("%lld %lld", &pos[i], &add[i]); } else if (typ == 2) { scanf("%lld", &mul[i]); } else { int len; scanf("%lld", &len); for (int j = 1, x; j <= len; j++) { scanf("%lld", &x); G1[x].push_back(i); G2[i].push_back(x); } } } int Q; scanf("%lld", &Q); for (int i = 1, x; i <= Q; i++) { scanf("%lld", &x); G1[x].push_back(0); G2[0].push_back(x); } cnt[0] = 1; topsort1(); topsort2(); for (int i = 1; i <= n; i++) (a[i] *= mul[0]) %= mod; for (int i = 1; i <= m; i++) (a[pos[i]] += cnt[i] * add[i] % mod) %= mod; for (int i = 1; i <= n; i++) printf("%lld ", a[i]); }


![【拓扑排序】P7077 [CSP-S2020] 函数调用 【拓扑排序】P7077 [CSP-S2020] 函数调用](http://www.mshxw.com/aiimages/31/511669.png)
