有 n n n个元素,进行一些函数的操作。
功能可分为三类:
考虑给这些函数的调用关系建图,得到一个DAG。
若无操作1,则用拓扑排序计算出每个函数调用后给全局乘上的值。
考虑算上操作1,那么对于一个加法后的乘法,会给加法的贡献也乘上一个权值,那么可以倒着进行一次拓扑排序,算出每个加法被乘上之后的贡献。
#include
#include
#include
#define int long long
const int mod = 998244353;
std::vector<int> G1[100001], G2[100001];
int n, m;
int a[100001], mul[100001], cnt[100001], pos[100001], add[100001], deg[100001];
void topsort1() {
std::queue<int> 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<int> 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]);
}