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\),显然是一个\(\text{DAG}\)图,那么先拓扑,将先后关系整一下,然后:

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

\[mul_i =mul_i \times \prod_{k \in \texttt{son}_i} mul_k\\ \]

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

\[add_{v_i} = add_{v_i} + add_x \times \prod_{k = i + 1} ^ {\texttt{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\n",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\n",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\n",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;
}
posted @ 2020-11-14 23:08  luyiming123  阅读(135)  评论(0编辑  收藏  举报