[CSP2020]函数调用

1.考虑只有类型1,2的操作的情况:

假设一个数组依次执行:a[1]+1, *3, a[1]+2, a[3]+2, *2 

那么 a[1] = a[1]*3*2 + 1*(3*2) + 2*2 , a[3] = a[3]*3*2 + 2*2 , 数组其余元素均乘上3*2=6倍

发现对于乘法操作,在最后给所有数组元素乘上就好了,

而一个加法操作带的系数就等于它后面的所有乘法操作之积

因此可以倒序处理,从后往前记录已进行的所有乘法操作的积是多少,这样就能计算出每次加法操作带的系数是多少

2.考虑类型3的操作:

  • 先考虑乘法:

对于图上的每个点(代表着一种操作),维护一个mul,表示执行一次这个操作会给累计的积乘上多少

对于1类操作,它的mul=1;对于2类操作,它的mul就等于它要乘上的值;而对于3类操作,它的mul等于它直接连向的所有点的mul之积

 

以样例2为例,点2的mul为2,点3的mul为3,所以点1的mul为6,那么执行一次操作1就会让前面执行过的所有的加法操作再乘上6的系数

由题目的条件易得,函数的调用关系构成一个DAG

按照拓扑序倒序扫一遍即可处理出mul

  • 再考虑加法:

对于每种类型1或3的操作,维护一个k,表示这个操作带着多少系数

先倒序处理 q 次操作,按照只有类型1,2的方法处理出k,

再把类型3的节点的k下传到它所包含的的类型1的节点,

即可处理出最终的k

  • 注意:有些类型3的操作既包含加法又包含乘法

为了确保答案的正确性,必须从后往前倒序处理所有调用的函数

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=1000005;
struct Edge{
    int v,nxt;
}edge[N];
ll a[N];
int n,m,Q,F[N],cnt,head[N],d[N],rnd[N],len;
queue<int> q;
struct func{
    int tp,p;
    ll v,mul,k;
}b[N];
void addedge(int u,int v){
    edge[++cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    d[v]++;
}
void tuopu(){
    for(int i=1;i<=m;i++) 
        if(!d[i]) q.push(i);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        rnd[++len]=u;
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].v;
            d[v]--;
            if(!d[v]) q.push(v);
        }
    }
}
void getmul(){
    for(int i=m;i>=1;i--){
        int u=rnd[i];
        for(int j=head[u];j;j=edge[j].nxt){
            int v=edge[j].v;
            b[u].mul=1ll*b[u].mul*b[v].mul%mod;
        }
    }
}
void getk(){
    for(int i=1;i<=m;i++){
        int u=rnd[i]; 
        ll now=1;
        for(int j=head[u];j;j=edge[j].nxt){
            int v=edge[j].v;
            b[v].k=(b[v].k+b[u].k*now%mod)%mod;
            now=now*b[v].mul%mod;
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) 
        scanf("%lld",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&b[i].tp);
        if(b[i].tp==1){
            scanf("%d%lld",&b[i].p,&b[i].v);
            b[i].mul=1;
        }
        else if(b[i].tp==2){
            scanf("%lld",&b[i].v);
            b[i].mul=b[i].v;
        }
        else{
            scanf("%d",&b[i].p);b[i].mul=1;
            for(int j=1,x;j<=b[i].p;j++){
                scanf("%d",&x);
                addedge(i,x);
            }
        }
    }
    tuopu();
    getmul();
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++) 
        scanf("%d",&F[i]);
    ll now=1;
    for(int i=Q;i>=1;i--){
        int x=F[i]; 
        b[x].k=(b[x].k+now)%mod;
        now=now*b[x].mul%mod;
    }
    getk();
    for(int i=1;i<=n;i++) a[i]=a[i]*now%mod;
    for(int i=1;i<=m;i++){
        if(b[i].tp==1)
            a[b[i].p]=(a[b[i].p]+b[i].v*b[i].k%mod)%mod;
    }
    for(int i=1;i<=n;i++) 
        printf("%lld ",a[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/HarryPotter-fan/p/14005216.html