95分求助
查看原帖
95分求助
376662
zixiangzhan楼主2021/9/19 23:00
#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define LL long long
#define il inline
#define re register
il int read()
{
	int s=0,w=1;char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') w=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s=(s<<1)+(s<<3)+c-'0';
		c=getchar();
	}
	return s*w;
}
il LL read_ll()
{
	LL s=0,w=1;char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') w=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s=(s<<1)+(s<<3)+c-'0';
		c=getchar();
	}
	return s*w;
}
const int N=100010;
const int M=1000010;
const LL mod=998244353;
int n,m,Q,op,rt;
LL a[N];
LL ad[N],mul[N],cnt[N];
int pos[N];
int zhan[N],n_zh;
int head1[N],ver1[M],nxt1[M],tot1,ru1[N];
int head2[N],ver2[M],nxt2[M],tot2,ru2[N];
queue<int> q;
/*
NOTE
ad:"add",对应某一1操作的V值 
mul:multiply,即调用这个函数后整个序列变成原来的几倍
cnt:某一函数被调用多少次 
要建立超级节点 
pos:1操作的P ,即1操作对应得下标 
"1""2"分别表示topo1,topo2使用的图,即分别为
反图/正图对应的变量 
(雀食十分别扭) 
*/ 
il void kkk1(int u,int v)
{
	ver1[++tot1]=v;
	nxt1[tot1]=head1[u];
	head1[u]=tot1;
}
il void kkk2(int u,int v)
{
	ver2[++tot2]=v;
	nxt2[tot2]=head2[u];
	head2[u]=tot2;
}
il void topo1()
{
	while(!q.empty()) q.pop();
	for(re int i=1;i<=rt;i++){
		if(ru1[i]==0) q.push(i);//!
	}
	while(q.size()){
		int xx=q.front();
		q.pop();
		for(re int i=head1[xx];i;i=nxt1[i]){
			int vv=ver1[i];
			mul[vv]=(mul[vv]*mul[xx])%mod;
			//跑反图的过程就相当于dfs回溯了,所以其实
			//记忆化搜索也行 
			ru1[vv]--;
			if(ru1[vv]==0) q.push(vv);
		}
	}
}
il void topo2()
{//正图反着跑可还行…… 
	while(!q.empty()) q.pop();
	for(re int i=1;i<=rt;i++){ 
		if(!ru2[i]) q.push(i);
	}
	while(q.size()){
		int xx=q.front();
		q.pop();
		LL now_mul=1LL;
		//当前函数内的乘法标记 
		for(re int i=head2[xx];i;i=nxt2[i]){
			/*这里注意要倒序遍历,因为每个函数执行完之后
			只影响在它前面执行的函数,而由于链表特性,
			正着挨个插进去之后,后插入的正好就在前面
			虽然这里考不考虑对结果没有影响,但是应该
			考虑这个问题*/ 
			int vv=ver2[i];
			cnt[vv]=(cnt[vv]+cnt[xx]*now_mul)%mod;
			now_mul=(now_mul*mul[vv])%mod;
			ru2[vv]--;
			if(ru2[vv]==0) q.push(vv); 
		}
	}
	return;
}
signed main()
{
	freopen("P7077_20.in","r",stdin);
	freopen("lz_P7077.out","w",stdout); 
	n=read();
	for(re int i=1;i<=n;i++) a[i]=read_ll();
	m=read(); 
	rt=m+1;//超级根节点,找点的时候一定不要忘了把超级根节点也
	//考虑到!!! 
	mul[rt]=1,cnt[rt]=1;
	for(re int i=1;i<=m;i++){
		op=read();
		if(op==1){
			pos[i]=read(),ad[i]=read(),mul[i]=1;
		}
		else if(op==2) mul[i]=read_ll();
		else if(op==3){
			mul[i]=1;
			ru1[i]=read();
			for(re int j=1;j<=ru1[i];j++){
				int vv=read();
				kkk2(i,vv);
				ru2[vv]++;
				zhan[++n_zh]=vv;
			}
			while(n_zh){
				kkk1(zhan[n_zh],i);
				zhan[n_zh--]=0;
			}
		}
	}
	Q=read();
	for(re int i=1;i<=Q;i++){
		int vv=read();
		kkk2(rt,vv);
		ru2[vv]++;
		zhan[++n_zh]=vv;
	}
	ru1[rt]=Q;
	while(n_zh){
		kkk1(zhan[n_zh],rt);
		zhan[n_zh--]=0;
	}
	topo1();//第一遍跑反图 
	topo2();//第二遍跑正图 
	for(re int i=1;i<=n;i++) a[i]=(a[i]*mul[rt])%mod;
	//因为每一次乘法操作都对原始序列有影响,而topo2并没
	//有进行这个操作 
	for(re int i=1;i<=m;i++){
		if(ad[i]!=0) a[pos[i]]=(a[pos[i]] + (cnt[i]*ad[i]%mod))%mod;
	}
	for(re int i=1;i<=n;i++){
		printf("%lld ",((a[i]%mod)+mod)%mod);
	}
	return 0;
}
2021/9/19 23:00
加载中...