1 条题解

  • 0
    @ 2026-9-2 1:52:21

    题目要求我们维护三种操作:

    1. 单点加;
    2. 区间乘;
    3. 依次调用函数。

    容易想到函数的调用关系构成了一张图,题目数据中的特殊性质“函数调用关系构成一棵树”和 Cj106∑C_j≤10^6 都给出了提示,而题目保证不会出现递归函数则说明这是一张有向无环图即 DAG。

    接下来考虑如何维护操作 1 和操作 2。

    先考虑操作 2,比较简单,直接把所有区间乘全部乘起来即可。具体地,建一个反向图,做一遍拓扑把所有的乘数乘到根节点上。

    再考虑操作 1。我们发现具体增加的数值比较难维护,因为在图中一个出度不为 0 的点可能有多个子节点。因此我们考虑维护加操作最终乘上的系数,这样就不用具体到某个加操作上了。
    cntucnt_uuu 操作中加操作乘上的系数,则有 cntu=cntu+cntv×nemulcnt_u=cnt_u+cnt_v\times nemul,其中 uuvv 当前子节点,nemulnemulvv 所有遍历过的子节点的乘数之积。拓扑跑一遍即可。


    注:

    1. 为了方便,我们可以用一个虚拟源点(节点 0)连向最后操作序列中的每个操作。
    2. 题目要求依次执行函数,所以要用邻接表存图。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1e5+10,mod=998244353;
    int n,p[N],v[N],d[N],m;
    LL mul[N],add[N],cnt[N],a[N];
    vector<int> e1[N],e2[N];//e1为正向图,e2为反向图
    void get_mul(){//乘数
        queue<int> q;
        for(int i=0;i<=m;i++){
            d[i]=e1[i].size();
            if(!d[i]) q.push(i);
        }
        while(q.size()){
            int t=q.front();
            q.pop();
            for(int j:e2[t]){
                mul[j]=mul[j]*mul[t]%mod;
                if(!--d[j]) q.push(j);
            }
        }
    }
    void get_cnt(){//加操作系数
        queue<int> q;
        for(int i=0;i<=m;i++){
            d[i]=e2[i].size();
            if(!d[i]) q.push(i);
        }
        while(q.size()){
            int t=q.front();
            q.pop();
            LL ne=1;
            for(int i=e1[t].size()-1;i>=0;i--){
                int j=e1[t][i];
                cnt[j]=(cnt[j]+cnt[t]*ne)%mod;
                ne=ne*mul[j]%mod;
                if(!--d[j]) q.push(j);
            }
        }
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        cin>>m;
        for(int i=1;i<=m;i++){
            mul[i]=1;
            int op;
            cin>>op;
            if(op==1) cin>>p[i]>>v[i];
            else if(op==2) cin>>mul[i];
            else{
                int c;
                cin>>c;
                while(c--){
                    int g;
                    cin>>g;
                    e1[i].push_back(g);
                    e2[g].push_back(i);
                }
            }
        }
        int q;
        cin>>q;
        while(q--){
            int x;
            cin>>x;
            e1[0].push_back(x);
            e2[x].push_back(0);
        }
        mul[0]=cnt[0]=1;
        get_mul(),get_cnt();
        for(int i=1;i<=n;i++) a[i]=a[i]*mul[0]%mod;
        for(int i=1;i<=m;i++) a[p[i]]=(a[p[i]]+cnt[i]*v[i])%mod;
        for(int i=1;i<=n;i++) cout<<a[i]<<" ";
        return 0;
    }
    
    • 1

    信息

    ID
    2010
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    9
    已通过
    3
    上传者