(题意略)
题解
显然这是一个拓扑图。每个加法的贡献是所有后缀积之和。于是先逆序(前向星自带逆序)DP 出每个点对应的积,在 DP 中途枚举到 (u o v) 的边时,把当前 (u) 的状态赋给 (u o v),再 DP (v),最后更新 (u) 的状态。然后每条到加法操作的路径代表着调用一次加法操作,其后缀和即为路径边权积。然后再 DP 一遍就能得到每个加法操作的贡献。
代码:
#include<bits/stdc++.h>
using namespace std;
int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
const int N=4e5+10,M=4e6+10,mod=998244353;
struct bian{
int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
++tot;
b[tot].l=1;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
int n,m,q;
int op[N],pos[N],val[N];
int f[N];
int dfn[N],dfnn=0;
int ss1(int x){
if(~f[x])return f[x];
if(op[x]==1){
f[x]=1;
}else if(op[x]==2){
f[x]=val[x];
}else{
f[x]=1;
for(int i=s[x];i;i=b[i].n){
b[i].l=f[x];
f[x]=f[x]*1ll*ss1(b[i].e)%mod;
}
}
dfn[++dfnn]=x;
return f[x];
}
bool vis[N];
int g[N];
int ans[N];
int main(){
n=getint();
op[0]=3;
for(int i=1;i<=n;i++){
add(0,i);
op[i]=1;
pos[i]=i;
val[i]=getint();
}
m=getint();
for(int i=n+1;i<=n+m;i++){
op[i]=getint();
if(op[i]==1)pos[i]=getint(),val[i]=getint();
else if(op[i]==2)val[i]=getint();
else{
int c=getint();
while(c--)add(i,getint()+n);
}
}
int q=getint();
for(int i=0;i<q;i++)add(0,getint()+n);
memset(f,-1,sizeof(f));
ss1(0);
g[0]=1;
for(int I=dfnn;I;--I){
int i=dfn[I];
for(int j=s[i];j;j=b[j].n){
int v=b[j].e;
g[v]=(g[v]+g[i]*1ll*b[j].l)%mod;
}
if(op[i]==1){
ans[pos[i]]=(ans[pos[i]]+g[i]*1ll*val[i])%mod;
}
}
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
// cerr<<"
Finished after "<<clock()/1000.0<<" second(s)."<<endl;
return 0;
}