CSP-S 2020 T3函数调用

题目大意

题解

这道题的难度大概是这次提高组最难的一题了,考试时一直在想线段树合并,发现时间过不了以后就放弃打了暴力。

关于这道题,可以容易发现,对于乘法操作,直接最后乘上即可,对于加法操作,只需要将加的数乘上后面乘的数就行了。

所以可以得出一个做法:

  1. 首先可以考虑反着做一次拓扑排序,求出每次操作中包含了多少次乘法操作。
  2. 然后从后往前扫一遍所有询问的操作,将乘法操作统计一下。
  3. 对于加法操作,发现乘上多少意味着重复了多少次这个操作,然后可以记录一下每个操作后面要经过多少次操作,然后再来一个拓扑排序,处理和一个加法操作同级的操作中后面要进行的乘法操作。

然后这道题就做完了。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 200000
#define M 2000000
#define ll long long
#define mo 998244353
using namespace std;
ll n,a[N],m,opt,Q,q[N],qp[N],num,p[N],sum;
ll i,j,k,data[N],x,y,val,tot;
struct edge{
	ll to,next;
}e[M],ep[M];
struct node{
	ll mul,add[3],out,in,times;
}f[N];
void insert(ll x,ll y){
	tot++;
	e[tot].to=y;
	e[tot].next=q[x];
	q[x]=tot;
}
void insertp(ll x,ll y){
	tot++;
	ep[tot].to=y;
	ep[tot].next=qp[x];
	qp[x]=tot;
}
int main(){
	freopen("call.in","r",stdin);
	freopen("call.out","w",stdout);
	scanf("%lld",&n);
	for (i=1;i<=n;i++) scanf("%lld",&a[i]);
	scanf("%lld",&m);
	for (i=1;i<=m;i++){
		scanf("%lld",&opt);
		f[i].mul=1;
		if (opt==1)
			scanf("%lld%lld",&f[i].add[1],&f[i].add[2]);
		if (opt==2)
			scanf("%lld",&f[i].mul);
		if (opt==3){
			scanf("%lld",&num);
			for (j=1;j<=num;j++){
				scanf("%lld",&x);
				insert(i,x);
				insertp(x,i);
				f[x].in++;
				f[i].out++;
			}
		}
	}
	j=0;
	for (i=1;i<=m;i++)
		if (!f[i].out){
			j++;
			data[j]=i;
		}
	i=0;
	while (i<j){
		i++;
		x=data[i];
		for (k=qp[x];k;k=ep[k].next){
			y=ep[k].to;
			f[y].mul=f[y].mul*f[x].mul%mo;
			f[y].out--;
			if (!f[y].out){
				j++;
				data[j]=y;
			}
		}
	}
	scanf("%lld",&Q);
	val=1;
	for (i=1;i<=Q;i++)
		scanf("%lld",&p[i]);
	for (i=Q;i>=1;i--){
		x=p[i];
		f[x].times=(f[x].times+val)%mo;
		val=val*f[x].mul%mo;
	}
	for (i=1;i<=n;i++) a[i]=a[i]*val%mo;
	j=0;
	for (i=1;i<=m;i++)
		if (!f[i].in){
			j++;
			data[j]=i;
		}
	i=0;
	while (i<j){
		i++;
		x=data[i];
		sum=f[x].times;
		for (k=q[x];k;k=e[k].next){
			y=e[k].to;
			f[y].times=(f[y].times+sum)%mo;
			sum=sum*f[y].mul%mo;
			f[y].in--;
			if (!f[y].in){
				j++;
				data[j]=y;
			}
		}
	}
	for (i=1;i<=m;i++) 
		if (f[i].add[1]) a[f[i].add[1]]=(a[f[i].add[1]]+f[i].times*f[i].add[2]%mo)%mo;
	for (i=1;i<=n;i++) printf("%lld ",a[i]);
	printf("\n");
	return 0;
}
posted @ 2020-11-12 19:35  Mohogany  阅读(255)  评论(0编辑  收藏  举报