P7077 函数调用(call)

说在前面

我又逊了,为了T1我T3都没开...

题意简述

(n)个数,为(a_1,a_2,cdots a_n)。有(m)个函数,每个函数可以如一下方式表示:

  • (T_i = 1)时,(P_i,V_i) (a_{P_i} leftarrow a_{P_i} + V_i)
  • (T_i = 2)时,(V_i) 所有数乘上(V_i)
  • (T_i = 3)时,(C_i,g_i^{(1)},g_{i}^{(2)},cdots g_{i}^{(C_i)}),表示调用这些函数,保证不出现环。

数据范围不想写了,/kk

简单口胡

u1s1,这题还是有一点意思的。
暴力:线段树

正解:

先考虑没有(T_i = 3)的时候怎么做。

我分别调用((T_i = 1,P_i = 1,V_i = 1),(T_i = 2,V_i = 2),(T_i = 1,P_i = 2,V_i = 2),(T_i = 2,V_i = 3))这几个鬼函数。

显然,如果我进行一个(T_i = 2)的操作,那么前面所有(T_i = 1)的操作所给(a_{P_i})带来的贡献(也就是(V_i))要翻(V_i)(T_i = 2)(V_i))倍。

换个角度,考虑每个(T_i = 1)的函数会被翻几倍,很容易想到后缀积。具体地,设(add_i)(i)函数被调用个数(翻的倍数),则易得

[add_i = prod_{k = i + 1} ^ n V_k[T_k = 2] ]

然后更新既珂。

转移到有(T_i = 3),显然是一个( ext{DAG})图,那么先拓扑,将先后关系整一下,然后:

(mul_i)为调用(i)后所乘的总积。

[mul_i =mul_i imes prod_{k in exttt{son}_i} mul_k\ ]

(add_i)求法有点不同,在我们处理到(x)时,去更新其子节点(v)

[add_{v_i} = add_{v_i} + add_x imes prod_{k = i + 1} ^ { exttt{size}} mul_{v_k} ]

于是这题没了。

注意求(add)时,注意调用先后顺序,一定是调用先的在前。

# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 2;
const long long mod = 998244353;
int n,m,q;
int F[N];
long long a[N];
long long mul[N],add[N],V[N];
int T[N],P[N];
int du[N],que[N];
vector <int> g[N];

template <typename T> void read(T &x)
{
    x = 0;
    int w = 1;
    char ch = getchar();
    while(!isdigit(ch))
    {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    x *= w;
    return;
}

void topsort(void)
{
    int cur = 0;
    queue <int> q;
    for(int i = 1; i <= m; i++)
    {
        if(!du[i]) q.push(i);
    }
    while(!q.empty())
    {
        int x = q.front();q.pop();
        que[++cur] = x;
        for(int i = 0; i < g[x].size(); i++)
        {
            int v = g[x][i];
                if(--du[v] == 0) 
                {
                    q.push(v);
                }
        }
    }
    return;
}

void Get1(void)
{
    for(int i = m; i >= 1; i--)
    {
        int x = que[i];
        // printf("x = %d
",x);
        for(int j = 0; j < g[x].size(); j++)
        {
            int v = g[x][j];
            mul[x] = (mul[x] * mul[v]) % mod;
            // printf("mul[%d] = %lld
",x,mul[x]);
        }
    }
    return;
}

void Get2(void)
{
    long long cur = 1;
    for(int i = 1; i <= m; i++)
    {
        int x =que[i];
        cur = 1;
        for(int j = g[x].size() - 1; j >= 0; j--)
        {
            int v = g[x][j];
            add[v] = (add[v] + add[x] * cur) % mod;
            cur = (cur * mul[v]) % mod;
        }
    }
    return;
}

int main(void)
{
    read(n);
    for(int i = 1; i <= n; i++)
    {
        read(a[i]);
    }
    read(m);
    for(int i = 1; i <= m; i++)
    {
        read(T[i]);
        if(T[i] == 1)
        {
            read(P[i]),read(V[i]);
            mul[i] = 1;
        }
        else
        {
            if(T[i] == 2)
            {
                read(V[i]);
                mul[i] = V[i];
            }
            else
            {
                mul[i] = 1;
                int c;
                read(c);
                for(int j = 1; j <= c; j++)
                {
                    int v;
                    read(v);
                    g[i].push_back(v);
                    du[v]++;
                }
            }
        }
    }
    topsort();
    Get1();
    read(q);
    for(int i = 1; i <= q; i++) read(F[i]);
    long long cur = 1;
    for(int i = q; i >= 1; i--)
    {
        add[F[i]] = (add[F[i]] + cur) % mod;
        cur = (cur * mul[F[i]]) % mod;
    }
    Get2();
    for(int i = 1; i <= n; i++) a[i] = (a[i] * cur) % mod;
    // for(int i = 1; i <= m; i++)
    // {
    //     printf("add[%d] = %lld
",i,add[i]);
    // }
    for(int i = 1; i <= m; i++)
    {
        if(T[i] == 1)
        {
            a[P[i]] = (a[P[i]] + V[i] * add[i] % mod) % mod;
        }
    }
    for(int i = 1; i <= n; i++)
    {
        printf("%lld ",a[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/luyiming123blog/p/P7077.html