CSP-2020 T3 函数调用

总结

在考场上因为看到这题时没多少时间了,草草的看了下题,就开始了数据结构暴力搞,后来发现要在递归里套递归,就放弃了(逃)。考后在吸收了他人的经验之后,前来补上。


题目传送门

这题刚看有点像数据结构,但经过仔细分析后,其实不是。它只需要单点修改和区间乘(如果真是数据结构,不至于这样);

如果我们把每个操作看作一个点,把每个类型为\(3\)的操作与它之后要调用的函数连一条边,再加上题目说了不会之间或间接的调用自己,即无环,那么它就是一个\(DAG\)。对于\(DAG\),那就有很多可以操作的了。

从题目入手,若操作为类型\(1\),及只需对某一个元素进行修改即可,若在它之后有类型为\(2\)的操作,将整个数列乘上\(k\),那么可以理解为这个类型为\(1\)的操作被执行了\(k\)次。那么,我们需要求出每个单点加的操作之后有多少个乘的操作,共乘了多少倍,记为\(sum\),仔细想一下,倒着来会好一些,因为我们不可能对于每个操作都单独去求一次\(sum\),所以肯定是一遍从后往前求,因为你后面求\(sum\)的对于前面的而言,也是需要的,前面求的又不会影响到你后面的。

至于顺序,就按着它给出的操作顺序倒着来。

然后对于每个操作在执行后会有多少乘积累加,我们用用拓扑序倒序来求,反正它都已经是个\(DAG\)了,记为\(mul\),在求\(sum\)前求出来。

不过需要注意的是,在你求出\(mul\)\(sum\)之后,还需要将\(sum\)下放,
file-list

就拿这个图来说,我们假设\(1\)节点的\(sum\)\(x\),那么\(+2\)这个操作的\(sum\)应格外增加\(3x\),同理\(+1\)\(sum\)应增加\(12x\)。(好像没搞很懂)

所以下传\(sum\)时,假设一个节点\(x\)\(sum\)\(S\),儿子为\(y\),从\(1\)\(k\)编号,那么\(y_i\)\(sum\)就应该增加

\[S\times \prod\limits_{j={i+1}}^kmul_j \]

最后遍历一遍即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
const int mod=998244353;
#define NEKO puts("NEKO")
#define ll long long
#define il inline
#define vocaloid(v) (v>='0'&&v<='9')
template <typename T>
il void read(T &x)
{
  x=0;int flag=1;char v=getchar();
  while(!vocaloid(v)) {if(v=='-') flag=-1;v=getchar();}
  while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
  x*=flag;
}
template <typename T>
il void write(T x)
{
  if(x<0) putchar('-'),x=-x;
  if(x>9) write(x/10);
  putchar(x%10+'0');
}
struct miku{
  int v,next;
}MIKU[maxn<<1];
struct Alone{
  int tp,pos;
  ll mul,sum,val;
}b[maxn];
ll a[maxn];
int n,m,Q,cnt,ord[maxn];
int h[maxn],in[maxn],opt[maxn],rin;
queue<int>q;
il void add(int u,int v)
{	
  MIKU[++cnt].next=h[u];
  MIKU[cnt].v=v;
  h[u]=cnt;
}
il void topo()
{
  for(int i=1;i<=m;i++) 
  	if(!in[i]) q.push(i);
  while(!q.empty())
  {
  	int x=q.front();q.pop();
  	opt[++rin]=x;
  	for(int i=h[x];i;i=MIKU[i].next)
  	{
  		int v=MIKU[i].v;
  		in[v]--;
  		if(!in[v]) q.push(v);
  	}
  }
}
il void dfs()
{
  for(int i=m;i>=1;i--)
  {
  	int x=opt[i];
  	for(int j=h[x];j;j=MIKU[j].next)
  	{
  		int v=MIKU[j].v;
  		b[x].mul=b[x].mul*b[v].mul%mod;
  	}
  }
}
il void down()
{
  for(int i=1;i<=m;i++)
  {
  	int x=opt[i];ll now=1;
  	for(int j=h[x];j;j=MIKU[j].next)
  	{
  		int v=MIKU[j].v;
  		b[v].sum=(b[v].sum+b[x].sum*now%mod)%mod;
  		now=now*b[v].mul%mod;
  	}
  }
}
int main()
{
  read(n);
  for(int i=1;i<=n;i++) read(a[i]);
  read(m);
  for(int i=1;i<=m;i++)
  {
  	read(b[i].tp);
  	if(b[i].tp==1)
  		read(b[i].pos),read(b[i].val),b[i].mul=1;
  	else if(b[i].tp==2)	
  		read(b[i].val),b[i].mul=b[i].val;
  	else
  	{
  		int x;read(b[i].pos);b[i].mul=1;
  		for(int j=1;j<=b[i].pos;j++)
  		{
  			read(x);add(i,x);
  			in[x]++;
  		}
  	}
  }
  topo();dfs();
  read(Q);ll now=1;
  for(int i=1;i<=Q;i++) read(ord[i]);
  for(int i=Q;i>=1;i--)
  {
  	int x=ord[i];b[x].sum=(b[x].sum+now)%mod;
  	now=now*b[x].mul%mod;
  }
  down();
  for(int i=1;i<=n;i++) a[i]=a[i]*now%mod;
  for(int i=1;i<=m;i++)
  	if(b[i].tp==1)
  		a[b[i].pos]=(a[b[i].pos]+b[i].val*b[i].sum%mod)%mod;
  for(int i=1;i<=n;i++) write(a[i]),printf(" ");
  return 0;
}
posted @ 2020-12-04 16:54  初雫  阅读(96)  评论(0编辑  收藏  举报