题解:P7077 [CSP-S2020] 函数调用
难道有人看题解不点赞的吗?
题目解析
我们发现题目一共有三种操作:单点加,区间乘,调用其他操作。我还以为是线段树……
接下来我们一步一步考虑:
如果没有第三种操作,那我们可以倒序遍历每个操作,维护每个元素加的次数
如果没有第二种操作,那我们就加一个
我们可以发现,其实上述两种情况可以合并,只要算出
好啦,下面是……
AC 代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+10,mod=998244353;
queue<ll> q;
vector<ll> e1[N],e2[N];
ll n,m,Q,a[N],t[N],p[N],v[N],in[N],mul[N],cnt[N];
void get_mul() {
for(ll i=0; i<=m; i++) {
in[i]=e2[i].size();
if(!in[i]) q.push(i);
}
while(!q.empty()) {
ll u=q.front();
q.pop();
for(ll v:e1[u]) {
mul[v]=mul[v]*mul[u]%mod;
in[v]--;
if(!in[v]) q.push(v);
}
}
}
void get_cnt() {
for(ll i=0; i<=m; i++) {
in[i]=e1[i].size();
if(!in[i]) q.push(i);
}
while(!q.empty()) {
ll u=q.front();
q.pop();
ll n_mul=1;
for(ll i=e2[u].size()-1; i>=0; i--) {//注意这里要到序遍历,因为后面的乘操作会影响前面的,但前面的不会影响后面的
ll v=e2[u][i];
cnt[v]=(cnt[v]+n_mul*cnt[u])%mod;
n_mul=n_mul*mul[v]%mod;
in[v]--;
if(!in[v]) q.push(v);
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(ll i=1; i<=n; i++) cin>>a[i];
cin>>m;
for(ll i=1; i<=m; i++) {
cin>>t[i];
mul[i]=1;
if(t[i]==1) cin>>p[i]>>v[i];
else if(t[i]==2) cin>>mul[i];
else {
ll c,g;
cin>>c;
while(c--) {
cin>>g;
e1[g].push_back(i);
e2[i].push_back(g);
}
}
}
cin>>Q;
mul[0]=cnt[0]=1;
while(Q--) {
ll f;
cin>>f;
e1[f].push_back(0);
e2[0].push_back(f);
}
get_mul(),get_cnt();
for(ll i=1; i<=n; i++) a[i]=a[i]*mul[0]%mod;
for(ll i=1; i<=m; i++)
if(t[i]==1) a[p[i]]=(a[p[i]]+cnt[i]*v[i])%mod;
for(ll i=1; i<=n; i++) cout<<a[i]<<" ";
return 0;
}
完结撒花~~