P7077 函数调用(call)
说在前面
我又逊了,为了T1我T3都没开...
题意简述
有\(n\)个数,为\(a_1,a_2,\cdots a_n\)。有\(m\)个函数,每个函数可以如一下方式表示:
- \(T_i = 1\)时,\(P_i,V_i\) \(a_{P_i} \leftarrow a_{P_i} + V_i\)
- \(T_i = 2\)时,\(V_i\) 所有数乘上\(V_i\)
- \(T_i = 3\)时,\(C_i,g_i^{(1)},g_{i}^{(2)},\cdots g_{i}^{(C_i)}\),表示调用这些函数,保证不出现环。
数据范围不想写了,/kk
简单口胡
u1s1,这题还是有一点意思的。
暴力:线段树
正解:
先考虑没有\(T_i = 3\)的时候怎么做。
我分别调用\((T_i = 1,P_i = 1,V_i = 1),(T_i = 2,V_i = 2),(T_i = 1,P_i = 2,V_i = 2),(T_i = 2,V_i = 3)\)这几个鬼函数。
显然,如果我进行一个\(T_i = 2\)的操作,那么前面所有\(T_i = 1\)的操作所给\(a_{P_i}\)带来的贡献(也就是\(V_i\))要翻\(V_i\)(\(T_i = 2\)的\(V_i\))倍。
换个角度,考虑每个\(T_i = 1\)的函数会被翻几倍,很容易想到后缀积。具体地,设\(add_i\)为\(i\)函数被调用个数(翻的倍数),则易得
\[add_i = \prod_{k = i + 1} ^ n V_k[T_k = 2]
\]
然后更新既珂。
转移到有\(T_i = 3\),显然是一个\(\text{DAG}\)图,那么先拓扑,将先后关系整一下,然后:
设\(mul_i\)为调用\(i\)后所乘的总积。
则
\[mul_i =mul_i \times \prod_{k \in \texttt{son}_i} mul_k\\
\]
\(add_i\)求法有点不同,在我们处理到\(x\)时,去更新其子节点\(v\),
\[add_{v_i} = add_{v_i} + add_x \times \prod_{k = i + 1} ^ {\texttt{size}} mul_{v_k}
\]
于是这题没了。
注意求\(add\)时,注意调用先后顺序,一定是调用先的在前。
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
const long long mod = 998244353;
int n,m,q;
int F[N];
long long a[N];
long long mul[N],add[N],V[N];
int T[N],P[N];
int du[N],que[N];
vector <int> g[N];
template <typename T> void read(T &x)
{
x = 0;
int w = 1;
char ch = getchar();
while(!isdigit(ch))
{
if(ch == '-') w = -1;
ch = getchar();
}
while(isdigit(ch))
{
x = x * 10 + ch - '0';
ch = getchar();
}
x *= w;
return;
}
void topsort(void)
{
int cur = 0;
queue <int> q;
for(int i = 1; i <= m; i++)
{
if(!du[i]) q.push(i);
}
while(!q.empty())
{
int x = q.front();q.pop();
que[++cur] = x;
for(int i = 0; i < g[x].size(); i++)
{
int v = g[x][i];
if(--du[v] == 0)
{
q.push(v);
}
}
}
return;
}
void Get1(void)
{
for(int i = m; i >= 1; i--)
{
int x = que[i];
// printf("x = %d\n",x);
for(int j = 0; j < g[x].size(); j++)
{
int v = g[x][j];
mul[x] = (mul[x] * mul[v]) % mod;
// printf("mul[%d] = %lld\n",x,mul[x]);
}
}
return;
}
void Get2(void)
{
long long cur = 1;
for(int i = 1; i <= m; i++)
{
int x =que[i];
cur = 1;
for(int j = g[x].size() - 1; j >= 0; j--)
{
int v = g[x][j];
add[v] = (add[v] + add[x] * cur) % mod;
cur = (cur * mul[v]) % mod;
}
}
return;
}
int main(void)
{
read(n);
for(int i = 1; i <= n; i++)
{
read(a[i]);
}
read(m);
for(int i = 1; i <= m; i++)
{
read(T[i]);
if(T[i] == 1)
{
read(P[i]),read(V[i]);
mul[i] = 1;
}
else
{
if(T[i] == 2)
{
read(V[i]);
mul[i] = V[i];
}
else
{
mul[i] = 1;
int c;
read(c);
for(int j = 1; j <= c; j++)
{
int v;
read(v);
g[i].push_back(v);
du[v]++;
}
}
}
}
topsort();
Get1();
read(q);
for(int i = 1; i <= q; i++) read(F[i]);
long long cur = 1;
for(int i = q; i >= 1; i--)
{
add[F[i]] = (add[F[i]] + cur) % mod;
cur = (cur * mul[F[i]]) % mod;
}
Get2();
for(int i = 1; i <= n; i++) a[i] = (a[i] * cur) % mod;
// for(int i = 1; i <= m; i++)
// {
// printf("add[%d] = %lld\n",i,add[i]);
// }
for(int i = 1; i <= m; i++)
{
if(T[i] == 1)
{
a[P[i]] = (a[P[i]] + V[i] * add[i] % mod) % mod;
}
}
for(int i = 1; i <= n; i++)
{
printf("%lld ",a[i]);
}
return 0;
}