题解 函数调用

题解 函数调用

题目链接

考场上居然没有想出来,看来我真是降智了。

题目分析

首先可以认为最后调用的一大堆函数是一个函数,也就是说最后只会执行一个函数。

分开考虑每个“将数据中的指定元素加上一个值”对数据造成的影响,当我们第 \(i\) 次操作执行了 \(a_p\gets a_p+v\) 时,以后的每一个乘法操作都会对增加的 \(v\) 造成影响,因为 \((a_p+v)\times s=a_p\times s+v\times s\) ,也就是说,如果我们可以知道后面进行的所有乘法操作究竟乘了多少的话,我们就可以直接得出这一次的加法操作给答案造成了多大的影响。

如果一个函数 \(u\) 依次调用了 \(v_1,v_2,\dots,v_c\) ,那么调用 \(v_{i+1},\dots,v_c\) 的时候给数据中的每一个元素乘上的值就会对调用函数 \(v_i\) 时使用的所有加法操作都额外乘上一个值,所以我们可以先求出每个函数总共给所有元素乘上了多大的值,记为 \(h_i\) ,然后令 \(u\)\(v_1,v_2,\dots,v_c\) 全部连一条边,其中 \(u\) 连向 \(v_i\) 的边的边权为 \(\prod_{j=i+1}^ch_{v_j}\) ,这样的话 \(u\)\(v\) 的路径条数表示的就是函数 \(u\) 调用函数 \(v\) 的次数, \(u\)\(v\) 的某条路径上的边边权的乘积就是从某次通过函数 \(u\) 通过某种途径调用到函数 \(v\) 到这次调用函数 \(u\) 结束的过程中将数据整体乘以了多少,所有路径边权乘积的和就是如果仅调用一次函数 \(u\) 函数 \(v\) 给答案造成贡献时需要乘以的系数。

求所有路径边权乘积的和直接 dp 就行了。

参考代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
	static char c;static int f;
	for(c=ch(),f=1;c<'0'||c>'9';c=ch())if(c=='-')f=-f;
	for(x=0;c>='0'&&c<='9';c=ch())x=x*10+(c&15);x*=f;
}
template<typename T>void write(T x){
	static char q[65];int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}
const int maxn=100005,maxm=100005,maxq=100005,maxc=1100005,mod=998244353;
int mo(const int x){return x>=mod?x-mod:x;}
struct Edge{
	int v,w,nt;
	Edge(int v=0,int w=0,int nt=0):
		v(v),w(w),nt(nt){}
}e[maxc*2];
int hd[maxm],num;
void qwq(int u,int v){
	e[++num]=Edge(v,0,hd[u]),hd[u]=num;
}
int d[maxm],q[maxm],CNT[maxm],a[maxn],TP[maxm],P[maxm],V[maxm],sm[maxm];
int main(){
	int n;read(n);
	for(int i=1;i<=n;++i)
		read(a[i]);
	int m;read(m);
	for(int i=1;i<=m;++i){
		int op;read(op);
		if(op==1){
			TP[i]=1;read(P[i]),read(V[i]);
		}
		else if(op==2){
			TP[i]=2;read(V[i]);
		}
		else{
			int c;read(c);
			for(int j=1;j<=c;++j){
				int s;read(s);qwq(i,s);qwq(s,i);
			}
		}
	}
	int Q;read(Q);
	for(int j=1;j<=Q;++j){
		int s;read(s);qwq(m+1,s);qwq(s,m+1);
	}
	for(int i=2;i<=num;i+=2)++d[e[i].v];int fro=0,bac=0;
	for(int i=1;i<=m+1;++i)if(d[i]==0)q[bac++]=i;
	while(fro<bac){
		int u=q[fro++];
		if(TP[u]==2)sm[u]=V[u];
		else sm[u]=1;
		for(int i=hd[u];i;i=e[i].nt){
			int v=e[i].v;
			if(i&1){
				e[i].w=sm[u];
				sm[u]=1ll*sm[u]*sm[v]%mod;
			}
			else{
				--d[v];
				if(d[v]==0)q[bac++]=v;
			}
		}
	}
	for(int i=1;i<=n;++i)a[i]=1ll*a[i]*sm[m+1]%mod;
	for(int i=1;i<=num;i+=2)++d[e[i].v];fro=bac=0;
	for(int i=1;i<=m+1;++i)if(d[i]==0)q[bac++]=i;CNT[m+1]=1;
	while(fro<bac){
		int u=q[fro++];
		if(TP[u]==1)a[P[u]]=mo(a[P[u]]+1ll*V[u]*CNT[u]%mod);
		for(int i=hd[u];i;i=e[i].nt)if(i&1){
			int v=e[i].v,w=e[i].w;
			CNT[v]=mo(CNT[v]+1ll*CNT[u]*w%mod);
			if((--d[v])==0)q[bac++]=v;
		}
	}
	for(int i=1;i<=n;++i)
		write(a[i]),pc(" \n"[i==n]);
	return 0;
}

posted @ 2020-11-08 15:25  xiaolilsq  阅读(279)  评论(0编辑  收藏  举报