P7077 函数调用(CSP-S2020 T3)

题目传送门

思路

考场上只花\(10min\)打了个\(10pts\)递归暴力跑路了。其实一眼看出是线段树2的板子,但是由于只剩半小时而且还没打\(T4\),所以果断放弃了。

其实这个题跟线段树完全没有关系,因为线段树最强的一点就是可以一边修改一边查询,但是本题只需要输出最后结果就行了,所以显然没有发挥出线段树的长处。然后仔细想了一个小时,思考出了个寂寞,果断看题解。看了五个小时终于看懂了,非常感动。

心态崩了,所以不想写思路,那些思路虽然已经深入我的脑海,但是我确实是不懂,只能把看懂的写在注释里。

最重要的思路其实就是倒着处理吧,因为只有先加后乘,乘上的数才能给加贡献,所以打标记的时候一定要倒着来。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1000005,mod=998244353;
int n,m,Q,k;
int in[N],f[N],op[N],p[N],qry[N];//f数组代表若第i个函数是类型1函数,则对第i个函数的加标记的贡献的倍数
ll a[N],mu=1,mul[N],w[N],add[N];//mul数组记录对全局乘标记的贡献,mu就是全局乘标记,add数组记录最后a数组乘完全局乘标记之后需要加上的数
bool vis[N];
vector<int> h[N];
queue<int> q;
void dfs(int num){//有点记搜的思想,先预处理所有的函数
	vis[num]=1;
	if(op[num]==2){
		mul[num]=w[num];
	}
	else{
		mul[num]=1;
	}
	for(int i=0;i<h[num].size();i++){
		int to=h[num][i];
		if(!vis[to]) dfs(to);
		mul[num]=mul[num]*mul[to]%mod;//更新一遍
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d",&op[i]);
		if(op[i]==1){
			scanf("%d%d",&p[i],&w[i]);
		}
		if(op[i]==2){
			scanf("%d",&w[i]);
		}
		if(op[i]==3){
			scanf("%d",&k);
			for(int j=1;j<=k;j++){
				int numm;
				scanf("%d",&numm);
				h[i].push_back(numm);
				in[numm]++;//为拓扑排序做准备
			}
		}
	}
	for(int i=1;i<=m;i++){
		if(!in[i]&&!vis[i]) dfs(i);//如果在其他函数内就不用单独再预处理一遍了,直接从入度为0的点开始dfs即可
	}
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++){
		scanf("%d",&qry[i]);
	}
	for(int i=Q;i>=1;i--){
		if(op[qry[i]]==1){
			f[qry[i]]=(f[qry[i]]+mu)%mod;
		}
		if(op[qry[i]]==2){
			mu=(w[qry[i]]*mu)%mod;
		}
		if(op[qry[i]]==3){
			f[qry[i]]=(f[qry[i]]+mu)%mod;
			mu=(mul[qry[i]]*mu)%mod;//三种函数分别对全局的影响
		}
	}
	for(int i=1;i<=Q;i++){
		if(!in[i]) q.push(i);
	}
	while(!q.empty()){
		int x=q.front();
		q.pop();
		if(op[x]==1) add[p[x]]=(add[p[x]]+f[x]*w[x]%mod)%mod;//这里入队的函数一定不可能再被3类型的函数更新了,因为它的入度已经是0了,所以可以直接更新最后的结果了
		for(int i=h[x].size()-1;i>=0;i--){//这里也要倒着处理
			int to=h[x][i];
			in[to]--;if(!in[to]) q.push(to);
			f[to]=(f[to]+f[x])%mod,f[x]=(f[x]*mul[to])%mod;
		}
	}
	for(int i=1;i<=n;i++){
		printf("%lld ",(a[i]*mu+add[i])%mod);
	}
	return 0;
}
posted @ 2020-12-01 21:47  徐明拯  阅读(116)  评论(0编辑  收藏  举报