解析
没做出来…
qwq
自己只能想到拓扑开vector把每个函数搞成一个奇怪的加法标记和乘法标记的结合
极限数据卡一卡还是nm的
得分纯玄学qwq
本题的关键是乘法相当于把函数调用多次
这样就可以利用和全是加法类似的策略拓扑统计每个函数的调用次数
使问题得以解决
要注意部分分的提示性!(尤其是特殊限制)
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
const int mod=998244353;
inline ll read() {
ll x=0ull,f=1ull;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int n,m;
struct node{
int to,nxt;
}p[N*10];
int fi[N],cnt;
inline void addline(int x,int y){
p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
ll mul[N],tim[N],a[N],add[N];
int du[N],pl[N];
int q[N],st,ed;
bool vis[N];
ll find(int x){
if(vis[x]) return mul[x];
vis[x]=1;
for(int i=fi[x];~i;i=p[i].nxt){
int to=p[i].to;
(mul[x]*=find(to))%=mod;
}
return mul[x];
}
void topu(){
st=1;ed=0;
for(int i=1;i<=m;i++){
if(!du[i]) q[++ed]=i;
}
while(st<=ed){
int x=q[st++];
//printf("x=%d tim=%lld\n",x,tim[x]);
ll now=1;
for(int i=fi[x];~i;i=p[i].nxt){
int to=p[i].to;
(tim[to]+=tim[x]*now)%=mod;
(now*=mul[to])%=mod;
--du[to];
if(!du[to]){
q[++ed]=to;
}
}
}
return;
}
int o[N];
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
memset(fi,-1,sizeof(fi));cnt=-1;
n=read();
for(int i=1;i<=n;i++) a[i]=read();
m=read();
for(int i=1;i<=m;i++){
int t=read();
if(t==1){
pl[i]=read();add[i]=read();mul[i]=1;
}
else if(t==2) mul[i]=read();
else{
mul[i]=1;
int k=read();
for(int j=1;j<=k;j++) o[j]=read();
for(int j=1;j<=k;j++){
du[o[j]]++;addline(i,o[j]);
}
}
}
for(int i=1;i<=m;i++){
if(!vis[i]) find(i);
//printf("i=%d mul=%lld\n",i,mul[i]);
}
int qq=read();
for(int i=1;i<=qq;i++) o[i]=read();
ll now=1;//printf("ok");
for(int i=qq;i>=1;i--){
(tim[o[i]]+=now)%=mod;
(now*=mul[o[i]])%=mod;
}
for(int i=1;i<=n;i++) a[i]=a[i]*now%mod;
topu();
for(int i=1;i<=m;i++){
(a[pl[i]]+=tim[i]*add[i])%=mod;
}
for(int i=1;i<=n;i++) printf("%lld ",a[i]);
}
/*
8 6
1 1 0 1 1 0
1 7
2 7
3 7
7 8
4 8
5 8
6 8
*/