• 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 imes prodlimits_{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;
    }
    
  • 相关阅读:
    VS 2012 + NDK + ADT 开发(Cocos2d-x 3.1开发)PART 2
    VS 2012 + NDK + ADT 开发(Cocos2d-x 3.1开发)PART 1
    WebView读取SD卡上的HTML
    安卓隐藏控件
    OMNET++安装
    产品质量的核心——概念的完整性
    关于异常
    基类与子类之间的引用转换
    成绩划分 处理异常
    《大道至简 第七、八章》读后感
  • 原文地址:https://www.cnblogs.com/MIKU5201314/p/14086690.html
Copyright © 2020-2023  润新知