正题
题目链接:https://www.luogu.com.cn/problem/P7077
题目大意
有一些函数分为三种
- 让一个位置的数加上一个数
- 让所有数乘上一个数
- 按顺序执行一些函数
然后不会有环,按顺序调用一些函数,求最后每个位置的数。
解题思路
我们发现对于一个乘操作其实就是相当于让前面的操作多执行若干次。
那么我们可以将一个333函数拆成:执行一些函数若干次然后最后乘上一个数。
那么我们可以做一次拓扑排序,然后反着求出每个函数最后乘上的那个数。
之后正着做,对于每个函数我们直接按照输入顺序反着(也就是邻接表顺序)枚举然后处理出每个函数要被该函数调用多少次,这样我们可以处理出每个函数的操作次数即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10,XJQ=998244353;
ll redin(){ll x=0,f=1;char c=getchar();while(!(c>='0'&&c<='9')){if(c=='-')f=-f;c=getchar();}while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
struct node{ll to,next;
}a[N*12];
ll n,m,tot,Q,ls[N],w[N],pos[N],val[N];
ll q[N],in[N],z[N],mul[N],ans[N];
void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;in[y]++;return;
}
void topsort(){ll tail=0,head=1;q[++tail]=n;for(ll i=1;i<n;i++)if(!in[i])q[++tail]=i;while(head<=tail){ll x=q[head++];for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;in[y]--;if(!in[y])q[++tail]=y;}}n=tail;return;
}
int main()
{m=redin();for(ll i=1;i<=m;i++)w[i]=redin();n=redin();for(ll i=1;i<=n;i++){ll op=redin();mul[i]=1;if(op==1)pos[i]=redin(),val[i]=redin();else if(op==2)mul[i]=redin();else if(op==3){ll k=redin(),y;for(ll j=1;j<=k;j++){y=redin();addl(i,y);}}}ll cnt=n;mul[++n]=1;Q=redin();while(Q--){ll x=redin();addl(n,x);}topsort();for(ll p=n;p>=1;p--){ll x=q[p];for(ll i=ls[x];i;i=a[i].next)mul[x]=mul[x]*mul[a[i].to]%XJQ;}z[q[1]]=1;for(ll p=1;p<=n;p++){ll x=q[p],g=1;for(ll i=ls[x];i;i=a[i].next){(z[a[i].to]+=z[x]*g%XJQ)%=XJQ;g=g*mul[a[i].to]%XJQ;}}for(ll i=1;i<=cnt;i++)ans[pos[i]]=(ans[pos[i]]+z[i]*val[i]%XJQ)%XJQ;for(ll i=1;i<=m;i++)printf("%lld ",(ans[i]+w[i]*mul[q[1]]%XJQ)%XJQ);return 0;
}