In mathematics you don't understand things, you just get used to them.

Description

大家应该都读过题。

Solution

赛后变摩托😃。

我们对每一个操作 $3$ 连边建图,然后可以知道只是一个 $\texttt{DAG}$。

考虑操作 $2$,我们只需要最后计算即可。

现在来看加法操作。我们设我们当前的操作为 $a_{p}\leftarrow a_{p}+v$,后面一共有 $k$ 个乘法操作,我们设为分别让序列整体乘上 $b_{1,2,\cdots,k}$。那么 $a_{p}\leftarrow a_{p}+v$ 一共会对最后的 $a_{p}$ 产生 $v\times\prod_{i=1}^{k}b_{i}$ 的贡献。

于是我们可以把操作离线下来,倒着来处理。

那么最后来考虑操作 $3$,我们来看操作 $3$ 连出的图。

对于图上的每一个节点我们维护一个值,表示执行后会带来的系数。

那么和操作 $1$ 类似的,我们对整张图进行拓扑,然后倒着处理,处理出每个节点的操作的加法计算了多少次,然后传播(指所有相邻节点)到加法操作的节点。

最后处理原序列即可。

(代码从 $\texttt{Vim}$ 里面复制出来可能缩进有问题)

#include <queue>
#include <cstdio>
#define mod ( 998244353 )

using namespace std;
typedef long long LL;

const int MAXN = 1e6 + 5;

template<typename _T>
void read( _T &x ){
    x = 0; char c = getchar(); _T f = 1;
    while( c < '0' || c > '9' ){ if( c == '-' )    f = -1; c = getchar(); }
    while( c >= '0' && c <= '9' ){ x = ( x << 3 ) + ( x << 1 ) + ( c & 15 ); c = getchar(); }
    x *= f;
}

template<typename _T>
void write( _T x ){
    if( x < 0 ){ putchar( '-' ); x = -x; }
    if( x > 9 )    write( x / 10 );
    putchar( x % 10 + '0' );
}

struct starS{
    int to, nxt;
    starS( int T = 0, int N = 0 ){ to = T; nxt = N; }
} as[MAXN * 2];

struct operateS{
    int Tp, pos;
    LL add, mul, sum;
    operateS( int T = 0, int P = 0, LL A = 0, LL M = 0, LL S = 0 ){ Tp = T; pos = P; add = A; mul = M; sum = S; }
} opS[MAXN];

int N, M, Q;
int totE, totT;
int A[MAXN], topS[MAXN], degS[MAXN], firS[MAXN], queS[MAXN];

void pushEdge( int u, int v ){ as[++ totE] = starS( v, firS[u] ); firS[u] = totE; }

void TopSort( ){
    queue<int> align;
    for( int i = 1; i <= M; ++ i ){
        if( ! degS[i] )    align.push( i );
    }
    while( ! align.empty( ) ){
        int u = align.front( ); align.pop( );
        topS[++ totT] = u;
        for( int i = firS[u]; i; i = as[i].nxt ){
            int v = as[i].to; degS[v] --;
            if( ! degS[v] ) align.push( v );
        }
    }
}

int main( ){
    read( N );
    for( int i = 1; i <= N; ++ i )  read( A[i] );
    read( M );
    for( int i = 1; i <= M; ++ i ){
        read( opS[i].Tp );
        if( opS[i].Tp == 1 ){
            read( opS[i].pos ); read( opS[i].add );
            opS[i].mul = 1;
        }
        else if( opS[i].Tp == 2 ) {
            read( opS[i].mul );
            opS[i].add = opS[i].mul;
        }
        else{
            read( opS[i].pos );
            opS[i].mul = 1;
            for( int j = 1, to; j <= opS[i].pos; ++ j ){ read( to ); pushEdge( i, to ); degS[to] ++; }
        }
    }
    TopSort( );
    for( int i = M; i; -- i ){
        int u = topS[i];
        for( int j = firS[u]; j; j = as[j].nxt ){
            int v = as[j].to;
            opS[u].mul = ( LL )opS[u].mul * opS[v].mul % mod;
        }
    }
    read( Q ); int now = 1;
    for( int i = 1; i <= Q; ++ i )  read( queS[i] );
    for( int i = Q; i; -- i ){ opS[queS[i]].sum = ( ( LL )opS[queS[i]].sum + now ) % mod; now = ( LL )now * opS[queS[i]].mul % mod; }
    for( int i = 1; i <= M; ++ i ){
        int u = topS[i], now = 1;
        for( int j = firS[u]; j; j = as[j].nxt ){
            int v = as[j].to;
            opS[v].sum = ( ( LL )opS[u].sum * now % mod + opS[v].sum ) % mod;
            now = ( LL )now * opS[v].mul % mod;
        }
    }
    for( int i = 1; i <= N; ++ i )  A[i] = ( LL )A[i] * now % mod;
        for( int i = 1; i <= M; ++ i ){
        if( opS[i].Tp == 1 )    A[opS[i].pos] = ( A[opS[i].pos] + ( LL )opS[i].add * opS[i].sum % mod ) % mod;
    }
    for( int i = 1; i <= N; ++ i )  write( A[i] ), putchar( ' ' );
    return 0;
}

graph theory

Solution Set -「CSP-S 2020」
Prev «
Record -「CSP-S 2020」赛后总结
» Next