zoukankan      html  css  js  c++  java
  • 【题解】[CSP-S 2020] 函数调用【拓扑图DP】

    题目链接

    题目链接

    (题意略)

    题解

    显然这是一个拓扑图。每个加法的贡献是所有后缀积之和。于是先逆序(前向星自带逆序)DP 出每个点对应的积,在 DP 中途枚举到 (u o v) 的边时,把当前 (u) 的状态赋给 (u o v),再 DP (v),最后更新 (u) 的状态。然后每条到加法操作的路径代表着调用一次加法操作,其后缀和即为路径边权积。然后再 DP 一遍就能得到每个加法操作的贡献。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int getint(){
    	int ans=0,f=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-')f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		ans=ans*10+c-'0';
    		c=getchar();
    	}
    	return ans*f;
    }
    const int N=4e5+10,M=4e6+10,mod=998244353;
    struct bian{
    	int l,e,n;
    };
    bian b[M];
    int s[N],tot=1;
    void add(int x,int y){
    	++tot;
    	b[tot].l=1;
    	b[tot].e=y;
    	b[tot].n=s[x];
    	s[x]=tot;
    }
    int n,m,q;
    int op[N],pos[N],val[N];
    int f[N];
    int dfn[N],dfnn=0;
    int ss1(int x){
    	if(~f[x])return f[x];
    	if(op[x]==1){
    		f[x]=1;
    	}else if(op[x]==2){
    		f[x]=val[x];
    	}else{
    		f[x]=1;
    		for(int i=s[x];i;i=b[i].n){
    			b[i].l=f[x];
    			f[x]=f[x]*1ll*ss1(b[i].e)%mod;
    		}
    	}
    	dfn[++dfnn]=x;
    	return f[x];
    }
    bool vis[N];
    int g[N];
    int ans[N];
    
    int main(){
    	n=getint();
    	op[0]=3;
    	for(int i=1;i<=n;i++){
    		add(0,i);
    		op[i]=1;
    		pos[i]=i;
    		val[i]=getint();
    	}
    	m=getint();
    	for(int i=n+1;i<=n+m;i++){
    		op[i]=getint();
    		if(op[i]==1)pos[i]=getint(),val[i]=getint();
    		else if(op[i]==2)val[i]=getint();
    		else{
    			int c=getint();
    			while(c--)add(i,getint()+n);
    		}
    	}
    	int q=getint();
    	for(int i=0;i<q;i++)add(0,getint()+n);
    	memset(f,-1,sizeof(f));
    	ss1(0);
    	g[0]=1;
    	for(int I=dfnn;I;--I){
    		int i=dfn[I];
    		for(int j=s[i];j;j=b[j].n){
    			int v=b[j].e;
    			g[v]=(g[v]+g[i]*1ll*b[j].l)%mod;
    		}
    		if(op[i]==1){
    			ans[pos[i]]=(ans[pos[i]]+g[i]*1ll*val[i])%mod;
    		}
    	}
    	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    	
    //	cerr<<"
    
    Finished after "<<clock()/1000.0<<" second(s)."<<endl;
    	return 0;
    }
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    「程序员思维训练」1. 读前声明
    获取apk的MD5或SHA1签名信息
    随用随记:超图小tips(长期更新ing)
    ajax上传大附件报错:413 Request Entity Too Large
    利用input file 上传文件调用ajax保存到服务器(含后台代码)
    软工课程总结
    开发体验心得总结
    结对项目 稳定版四则运算系统
    Week3 关于“微软必应词典客户端”的案例分析
    Week2 代码复查
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/13947645.html
Copyright © 2011-2022 走看看