CSP 2020 T3 函数调用

description

solution:

总的来说有三种操作

  • 单点加
  • 区间乘
  • 依次进行的函数调用

显然最麻烦的是3操作
容易发现所有3操作形成一个\(DAG\),我们考虑如何再\(DAG\)上操作(容易发现出度为\(0\)的点都是1操作或2操作)
首先有一个神奇的想法:对于每次加法操作(假设加上\(v\)),我们只要求出它的后缀积(设为\(mul\))那么最后相当于加上了\(v\times mul\)
于是我们可以先求出每个点对应的积
然后离线下所有修改,从后往前扫描,不断累乘后缀积作为当前节点的\(tag\)
然后在\(DAG\)上按照拓扑序依次下放标记,具体来说:

  • 当前节点为1操作,那么在对应位置加上值\(*\)后缀积即可
  • 当前节点为2操作,直接忽略
  • 当前节点为3操作,逆序遍历它指向的点(链式前向星自带逆序),下传标记后乘上当前遍历到的点对应的积

然后这道我认为本次考试出的最好的题目就结束了

code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,mod=998244353;
int n,m,q,tot,a[N],opt[N],p[N],v[N],d[N],qu[N];
int fi[N],ne[N<<4],to[N<<4],tops[N],deg[N],mul[N],tag[N];
inline void adde(int x,int y)
{
	ne[++tot]=fi[x],fi[x]=tot,to[tot]=y;
}
struct cmp{bool operator()(const int&x,const int&y){return tops[x]<tops[y];}};
inline int add(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline void pre()
{
	for(int i=1;i<=tot;++i)++deg[to[i]];
	queue<int>q;
	for(int i=1;i<=m;++i)if(!deg[i])q.push(i),tops[i]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=fi[u];i;i=ne[i])
		{
			int v=to[i];
			if(!(--deg[v]))q.push(v),tops[v]=tops[u]+1;
		}
	}
	for(int i=1;i<=m;++i)d[i]=i;
	sort(d+1,d+m+1,cmp());
	for(int i=m;i>=1;--i)
	{
		int u=d[i];
		mul[u]=1;
		if(opt[u]==2)mul[u]=v[u];
		for(int j=fi[u];j;j=ne[j])
		{
			int v=to[j];
			mul[u]=1ll*mul[u]*mul[v]%mod;
		}
	}
}
inline void solve()
{
	for(int i=1;i<=m;++i)
	{
		int u=d[i];
		if(opt[u]==1)a[p[u]]=add(a[p[u]],1ll*v[u]*tag[u]%mod);
		for(int j=fi[u];j;j=ne[j])
		{
			int v=to[j];
			tag[v]=add(tag[v],tag[u]);
			tag[u]=1ll*tag[u]*mul[v]%mod;
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",a+i);
	scanf("%d",&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d",opt+i);
		if(opt[i]==1)scanf("%d%d",p+i,v+i);
		else if(opt[i]==2)scanf("%d",v+i);
		else 
		{
			int num;scanf("%d",&num);
			while(num--){int x;scanf("%d",&x);adde(i,x);}
		}
	}
	pre();int t=1;
	scanf("%d",&q);
	for(int i=1;i<=q;++i)scanf("%d",qu+i);
	for(int i=q;i>=1;--i)
	{
		int u=qu[i];
		if(opt[u]==1)tag[u]=add(tag[u],t);
		else if(opt[u]==2)t=1ll*t*mul[u]%mod;
		else tag[u]=add(tag[u],t),t=1ll*t*mul[u]%mod;
	}
	for(int i=1;i<=n;++i)a[i]=1ll*a[i]*t%mod;
	solve();
	for(int i=1;i<=n;++i)printf("%d ",a[i]);
	return 0;
}
posted @ 2020-11-10 19:05  BILL666  阅读(133)  评论(0编辑  收藏  举报