题解 函数调用

题解 函数调用

题目链接

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

题目分析

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

分开考虑每个“将数据中的指定元素加上一个值”对数据造成的影响,当我们第 (i) 次操作执行了 (a_pgets a_p+v) 时,以后的每一个乘法操作都会对增加的 (v) 造成影响,因为 ((a_p+v) imes s=a_p imes s+v imes 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(" 
"[i==n]);
	return 0;
}

原文地址:https://www.cnblogs.com/lsq147/p/13944477.html