CSP-S T3 函数调用

事先声明,考试时由于本人太菜,T1写了两个小时还tm没判12.31挂了所以只是口胡了个拓扑排序,直接打了40分,考完自闭了很久之后才码出来

首先我们发现由于不会递归,所以把所有操作连起来会形成一张DAG,DAG上并没有什么很好的数据结构可以维护,所以可以考虑分别考虑乘法和加法的影响,可以发现,最终值是初始值乘以一堆值再加上一堆值

又因为乘法显然会对加法产生影响所以可以考虑,每个加法到最后都会加几次

可以发现每个加法最后加几次,等价于在这个加法之后,全局乘的数值的积,于是我们可以考虑倒着处理这个函数数列

每次加法的时候就加上标记,(前面乘的积),乘法就更新全局积,如果是递归,就先给它下辖(即最终会被调用的乘法或者加法)的所有加法加上标记(打在它本身上面,最终拓扑排序下传),然后再用下面的乘法更新全局积

最后打完标记最后拓扑排序下传一下就行.具体地依然从后往前处理,注意要更新一下最终加法的次数(类似于线段树合并,处理右儿子时要考虑左儿子的贡献),具体看代码吧

其实也不是很难,还是我太菜了

/*call*/
#include<bits/stdc++.h>
using namespace std;
int read(){
    char c = getchar();
    int x = 0;
    while(c < '0' || c > '9')        c = getchar();
    while(c >= '0' && c <= '9')        x = x * 10 + c - 48,c = getchar();
    return x;
}
const int maxn = 1e6 + 10;
struct Edge{
    int nxt,point;
}edge[maxn<<1];
int a[maxn];
int head[maxn],tot;
int deg[maxn];
void add_edge(int x,int y){
    edge[++tot].nxt = head[x];
    edge[tot].point = y;
    head[x] = tot;
    deg[y]++;
}
struct Func{
    int op;
    int p,v;
}f[maxn];
int seq[maxn];
int C = 1;
int tag[maxn];
#define mod 998244353
int mul[maxn];
void add(int &x,int y){
    x += y - mod;
    x += (x >> 31) & mod;
}
void sol(int x){
    if(f[x].op == 1){
        add(tag[f[x].p],1ll * C * f[x].v % mod) ;
        return;
    }
    else if(f[x].op == 2){
        C = 1ll * C * f[x].v % mod;
    }
    else{
        for(int i = head[x]; i; i = edge[i].nxt){
            sol(edge[i].point);
        }
    }
}
void dfs(int x){
    if(~mul[x])    return;
    mul[x] = 1;
    if(f[x].op == 1)    return;
    if(f[x].op == 2){
        mul[x] = f[x].v;
        return;
    }
    for(int i = head[x]; i ; i = edge[i].nxt)        dfs(edge[i].point),mul[x] = 1ll * mul[x] * mul[edge[i].point] % mod;
}
int q[maxn];
int main(){
    int n = read();
    for(int i = 1; i <= n; ++i)        a[i] = read();
    int m = read();
    for(int i = 1; i <= m; ++i){
        int op = read();
        f[i].op = op;
        if(op == 1){
            f[i].p = read(),f[i].v = read();
        }
        else if(op == 2){
            f[i].v = read();
        }
        else{
            int s = read();
            for(int j = 1; j <= s; ++j){
                int x = read();
                add_edge(i,x);
            }
        }
    }
    memset(mul,-1,sizeof(mul));
    int t = read();
    for(int i = 1; i <= t; ++i)        seq[i] = read();
    for(int i = 1; i <= m; ++i)        dfs(i); 
    for(int x = t; x; --x){
        if(f[seq[x]].op == 1)        add(tag[seq[x]],C);
        if(f[seq[x]].op == 2)        C = 1ll * C * f[seq[x]].v % mod;
        if(f[seq[x]].op == 3){
            add(tag[seq[x]],C);
            C = 1ll * C * mul[seq[x]] % mod;
        }
    }
    for(int i = 1; i <= n; ++i)        a[i] = 1ll * a[i] * C % mod;
    int l = 1,r = 0;
    for(int i = 1; i <= m; ++i)        if(!deg[i])        q[++r] = i;
    while(l <= r){
        int x = q[l++];
        if(f[x].op == 1){
            add(a[f[x].p],1ll * tag[x] * f[x].v % mod);
            continue;
        }
        if(f[x].op == 2)    continue;
        int v = 1;
        for(int i = head[x]; i ; i = edge[i].nxt){
            int y = edge[i].point;
            add(tag[y],1ll * tag[x] * v % mod);
            --deg[y];if(!deg[y])    q[++r] = y;
            v = 1ll * v * mul[y] % mod;
        }
    }
    for(int i = 1; i <= n; ++i)        printf("%d%c",a[i]," \n"[i == n]);
    return 0;
}

 

posted @ 2020-11-09 13:45  y_dove  阅读(439)  评论(2编辑  收藏  举报