P7077 [CSP-S2020] 函数调用
题意

分析
直接线段树合并似乎复杂度不太对,会被卡。
于是考虑线性做法,发现原题的每一个函数的调用关系构成一个DAG。
由部分分启示我们先想想只有1操作的情况:直接每次暴力单点加,最后查询一次就行了。
再看只有前两个的情况:每次还是暴力单点加,但是要统计一下这个操作后面一共乘了多少倍,那么我们可以看做这个加法执行了这么多倍次。
现在加上第三个操作,函数的存在让我们不能直接递归下去再用二情况的方法了,但是我们发现其实这样也无非是很多的单点加,可以只统计造成的次数的影响。
考虑这样处理:
现在我们只对于每一个操作来统计在这之后乘了多少倍。
这个过程我们可以通过一次\(dfs\)来实现,相当于每一个乘法的权值是\(val\),然后其他的初始值都是\(1\),接下来按照 \(\prod_{v\in son[u]}{val[v]}\) 计算每一个节点的值即可。
然后统计倍数就是后缀的乘积了。
然后把这个次数递归到子节点去。
同时,我们在上一步的过程中,需要从后往前遍历子节点,并记录沿途的乘数之积。
因为我们在调用同一个函数前面的操作的时候,后面的乘法也会对前面的加法造成影响。
所以把次数递归到子节点的时候,还要乘上当前的乘数。
最后在叶子节点的加法,我们直接算一下贡献即可,同时记得使用最后的倍数乘以原本的每一个数。
代码
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
#define pb push_back
const int N=1e6+5,M=1e6+6;
const ll MOD=998244353;
int n,m,q,tp[N],id[N],in[N];
ll val[N],mul[N],add[N],pos[N],Mul[N],num[N];
vector<int>vec[N];
bool vis[N];
inline ll inc(ll x,ll y){return x+y>=MOD?x+y-MOD:x+y;}
void dfs(int x){
if(vis[x]) return ;
vis[x]=true;
const int len=vec[x].size();
for(int y:vec[x]) dfs(y),mul[x]=mul[x]*mul[y]%MOD;
return ;
}
void topusort(){
queue<int>q;
for(int i=1;i<=m;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front();q.pop();
const int len=vec[x].size();
ll MUL=1;
for(int i=len-1;i>=0;i--){
int y=vec[x][i];
num[y]=inc(num[y],MUL*num[x]%MOD);
in[y]--;
if(!in[y]) q.push(y);
MUL=MUL*mul[y]%MOD;
}
}
return ;
}
signed main(){
read(n);
for(int i=1;i<=n;i++) read(val[i]);
read(m);
for(int i=1;i<=m;i++){
read(tp[i]);mul[i]=1;
if(tp[i]==1) read(pos[i]),read(add[i]);
else if(tp[i]==2) read(mul[i]);
else{
int len;read(len);
for(int j=1,x;j<=len;j++) read(x),vec[i].pb(x),in[x]++;
}
}
for(int i=1;i<=m;i++) if(!vis[i]) dfs(i);
read(q);
for(int i=1;i<=q;i++) read(id[i]);
Mul[q+1]=1;
for(int i=q;i>=1;i--){
Mul[i]=Mul[i+1]*mul[id[i]]%MOD;
num[id[i]]=inc(num[id[i]],Mul[i+1]);
}
topusort();
for(int i=1;i<=n;i++) val[i]=val[i]*Mul[1]%MOD;
for(int i=1;i<=m;i++) if(tp[i]==1) val[pos[i]]=inc(val[pos[i]],add[i]*num[i]%MOD);
for(int i=1;i<=n;i++) write(val[i]),putchar(' ');
return 0;
}

浙公网安备 33010602011771号