CSP2020&洛谷P7077:函数调用

解析

没做出来…
qwq
自己只能想到拓扑开vector把每个函数搞成一个奇怪的加法标记和乘法标记的结合
极限数据卡一卡还是nm的
得分纯玄学qwq

本题的关键是乘法相当于把函数调用多次
这样就可以利用和全是加法类似的策略拓扑统计每个函数的调用次数
使问题得以解决

要注意部分分的提示性!(尤其是特殊限制)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
const int mod=998244353;
inline ll read() {
	ll x=0ull,f=1ull;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
int n,m;
struct node{
	int to,nxt;
}p[N*10];
int fi[N],cnt;
inline void addline(int x,int y){
	p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
ll mul[N],tim[N],a[N],add[N];
int du[N],pl[N];
int q[N],st,ed;
bool vis[N];
ll find(int x){
	if(vis[x]) return mul[x];
	vis[x]=1;
	for(int i=fi[x];~i;i=p[i].nxt){
		int to=p[i].to;
		(mul[x]*=find(to))%=mod;
	}
	return mul[x];
}
void topu(){
	st=1;ed=0;
	for(int i=1;i<=m;i++){
		if(!du[i]) q[++ed]=i;
	}
	while(st<=ed){
		int x=q[st++];
		//printf("x=%d tim=%lld\n",x,tim[x]);
		ll now=1;
		for(int i=fi[x];~i;i=p[i].nxt){
			int to=p[i].to;
			(tim[to]+=tim[x]*now)%=mod;
			(now*=mul[to])%=mod;
			--du[to];
			if(!du[to]){
				q[++ed]=to;
			}
		}
	}
	return;
}
int o[N];
int main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	memset(fi,-1,sizeof(fi));cnt=-1;
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	m=read();
	for(int i=1;i<=m;i++){
		int t=read();
		if(t==1){
			pl[i]=read();add[i]=read();mul[i]=1;
		}
		else if(t==2) mul[i]=read();
		else{
			mul[i]=1;
			int k=read();
			for(int j=1;j<=k;j++) o[j]=read();
			for(int j=1;j<=k;j++){
				du[o[j]]++;addline(i,o[j]);
			}
		}
	}
	for(int i=1;i<=m;i++){
		if(!vis[i]) find(i);
		//printf("i=%d mul=%lld\n",i,mul[i]);
	}
	int qq=read();
	for(int i=1;i<=qq;i++) o[i]=read();
	ll now=1;//printf("ok");
	for(int i=qq;i>=1;i--){
		(tim[o[i]]+=now)%=mod;
		(now*=mul[o[i]])%=mod;
	}
	for(int i=1;i<=n;i++) a[i]=a[i]*now%mod;
	topu();
	for(int i=1;i<=m;i++){
		(a[pl[i]]+=tim[i]*add[i])%=mod;
	}
	for(int i=1;i<=n;i++) printf("%lld ",a[i]);
}
/*
8 6
1 1 0 1 1 0
1 7
2 7
3 7
7 8
4 8
5 8
6 8
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值