题解 函数调用
题解 函数调用
考场上居然没有想出来,看来我真是降智了。
题目分析
首先可以认为最后调用的一大堆函数是一个函数,也就是说最后只会执行一个函数。
分开考虑每个“将数据中的指定元素加上一个值”对数据造成的影响,当我们第 \(i\) 次操作执行了 \(a_p\gets a_p+v\) 时,以后的每一个乘法操作都会对增加的 \(v\) 造成影响,因为 \((a_p+v)\times s=a_p\times s+v\times s\) ,也就是说,如果我们可以知道后面进行的所有乘法操作究竟乘了多少的话,我们就可以直接得出这一次的加法操作给答案造成了多大的影响。
如果一个函数 \(u\) 依次调用了 \(v_1,v_2,\dots,v_c\) ,那么调用 \(v_{i+1},\dots,v_c\) 的时候给数据中的每一个元素乘上的值就会对调用函数 \(v_i\) 时使用的所有加法操作都额外乘上一个值,所以我们可以先求出每个函数总共给所有元素乘上了多大的值,记为 \(h_i\) ,然后令 \(u\) 向 \(v_1,v_2,\dots,v_c\) 全部连一条边,其中 \(u\) 连向 \(v_i\) 的边的边权为 \(\prod_{j=i+1}^ch_{v_j}\) ,这样的话 \(u\) 到 \(v\) 的路径条数表示的就是函数 \(u\) 调用函数 \(v\) 的次数, \(u\) 到 \(v\) 的某条路径上的边边权的乘积就是从某次通过函数 \(u\) 通过某种途径调用到函数 \(v\) 到这次调用函数 \(u\) 结束的过程中将数据整体乘以了多少,所有路径边权乘积的和就是如果仅调用一次函数 \(u\) 函数 \(v\) 给答案造成贡献时需要乘以的系数。
求所有路径边权乘积的和直接 dp 就行了。
参考代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
static char c;static int f;
for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>void write(T x){
static char q[65];int cnt=0;
if(x<0)pc('-'),x=-x;
q[++cnt]=x%10,x/=10;
while(x)
q[++cnt]=x%10,x/=10;
while(cnt)pc(q[cnt--]+'0');
}
const int maxn=100005,maxm=100005,maxq=100005,maxc=1100005,mod=998244353;
int mo(const int x){return x>=mod?x-mod:x;}
struct Edge{
int v,w,nt;
Edge(int v=0,int w=0,int nt=0):
v(v),w(w),nt(nt){}
}e[maxc*2];
int hd[maxm],num;
void qwq(int u,int v){
e[++num]=Edge(v,0,hd[u]),hd[u]=num;
}
int d[maxm],q[maxm],CNT[maxm],a[maxn],TP[maxm],P[maxm],V[maxm],sm[maxm];
int main(){
int n;read(n);
for(int i=1;i<=n;++i)
read(a[i]);
int m;read(m);
for(int i=1;i<=m;++i){
int op;read(op);
if(op==1){
TP[i]=1;read(P[i]),read(V[i]);
}
else if(op==2){
TP[i]=2;read(V[i]);
}
else{
int c;read(c);
for(int j=1;j<=c;++j){
int s;read(s);qwq(i,s);qwq(s,i);
}
}
}
int Q;read(Q);
for(int j=1;j<=Q;++j){
int s;read(s);qwq(m+1,s);qwq(s,m+1);
}
for(int i=2;i<=num;i+=2)++d[e[i].v];int fro=0,bac=0;
for(int i=1;i<=m+1;++i)if(d[i]==0)q[bac++]=i;
while(fro<bac){
int u=q[fro++];
if(TP[u]==2)sm[u]=V[u];
else sm[u]=1;
for(int i=hd[u];i;i=e[i].nt){
int v=e[i].v;
if(i&1){
e[i].w=sm[u];
sm[u]=1ll*sm[u]*sm[v]%mod;
}
else{
--d[v];
if(d[v]==0)q[bac++]=v;
}
}
}
for(int i=1;i<=n;++i)a[i]=1ll*a[i]*sm[m+1]%mod;
for(int i=1;i<=num;i+=2)++d[e[i].v];fro=bac=0;
for(int i=1;i<=m+1;++i)if(d[i]==0)q[bac++]=i;CNT[m+1]=1;
while(fro<bac){
int u=q[fro++];
if(TP[u]==1)a[P[u]]=mo(a[P[u]]+1ll*V[u]*CNT[u]%mod);
for(int i=hd[u];i;i=e[i].nt)if(i&1){
int v=e[i].v,w=e[i].w;
CNT[v]=mo(CNT[v]+1ll*CNT[u]*w%mod);
if((--d[v])==0)q[bac++]=v;
}
}
for(int i=1;i<=n;++i)
write(a[i]),pc(" \n"[i==n]);
return 0;
}