我好蠢啊。。。

考试的时候不会写,现在看了这么多篇题解还是似懂非懂,所以决定写一下草稿。。。

草稿 和 题解

就是首先,题目保证了函数不会间接的调用其本身,所以可以直接知道这是一个 \(\text{DAG}\) ,从这个角度去考虑。

然后我们考虑对于两种操作,乘法的操作最后乘一下即可,但是对于加法操作,我们需要知道其之后的乘法对于自己的贡献。

因为要保证复杂度,所以这个东西是不能多次 \(\text{top}\) 来维护的。所以我们考虑如何在 \(\text{DAG}\) 上直接搞这个玩意儿。

我们可以先在每个节点处理出来如果选择他,你可以给后面的节点贡献多少的系数。这个东西一个 \(\text{top}\) 即可。然后可以考虑从后往前更新,用一个变量来维护到目前为止,你已经给整一个全局贡献了多少的变量,然后对于每一个点,在其前面进行的乘法操作也是需要考虑的。

最后再进行一次 \(\text{top}\) 将每个点的系数下传一下,下传的方法和之前类似,同时统计一下加法操作的贡献就可以了。

终于明白了!!!

感悟

高妙,高妙!

感觉自己对于 \(\text{top}\) 排序的理解都加深了。感觉跟有一些 \(\text{DP}\) 的思路有一点像,我们将贡献后置,然后再依次推出当前的系数是多少。

高妙,高妙!

代码

#include<bits/stdc++.h>
using namespace std;
#define Lint long long
inline int read()
{
char c=getchar();int x=0;
while(c<'0'||c>'9') c=getchar();
while('0'<=c&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
const int N=1e5+5,M=1e5+5,Q=1e5+5,E=1e6+5;
const Lint MOD=998244353;
int n,m;Lint a[N];int c[Q];
struct Point{Lint mul,coe,add;int tag,pos;}b[M];
struct Edge{int nxt,to;}e[2][E];int fir[2][M],deg[M],size[2];
void add(int u,int v,int tag){e[tag][++size[tag]]=(Edge){fir[tag][u],v},fir[tag][u]=size[tag];}
queue<int> q;
int topn[N],cnt=0;
void top()
{
for(int i=1;i<=m;++i) if(deg[i]==0) q.push(i);
while(!q.empty())
{
int tmp=q.front();q.pop();
topn[++cnt]=tmp;
for(int i=fir[0][tmp];i;i=e[0][i].nxt)
{
deg[e[0][i].to]--;
if(!deg[e[0][i].to]) q.push(e[0][i].to);
}
}
}
int opt[Q];
int main()
{
// freopen("call.in","r",stdin);
// freopen("call.out","w",stdout);
n=read();
for(int i=1;i<=n;++i) a[i]=read();
m=read();
for(int i=1;i<=m;++i)
{
b[i].tag=read(),b[i].mul=1;
if(b[i].tag==1) b[i].pos=read(),b[i].add=read();
if(b[i].tag==2) b[i].mul=read();
if(b[i].tag==3)
{
deg[i]=read();
for(int j=1,v;j<=deg[i];++j)
v=read(),add(v,i,0),add(i,v,1);
}
}
top();
for(int i=1;i<=m;++i)
{
for(int j=fir[0][topn[i]];j;j=e[0][j].nxt)
b[e[0][j].to].mul*=b[topn[i]].mul,b[e[0][j].to].mul%=MOD;
}
int q=read();
for(int i=1;i<=q;++i) c[i]=read();
Lint now=1;
for(int i=q;i>=1;--i)
{
b[c[i]].coe+=now,b[c[i]].coe%=MOD;
now*=b[c[i]].mul,now%=MOD;
}
for(int i=1;i<=n;++i) a[i]*=now,a[i]%=MOD;
for(int i=m;i>=1;--i)
{
Lint now=1;
for(int j=fir[1][topn[i]];j;j=e[1][j].nxt)
{
b[e[1][j].to].coe+=b[topn[i]].coe*now%MOD,b[e[1][j].to].coe%=MOD;
now*=b[e[1][j].to].mul,now%=MOD;
}
}
for(int i=1;i<=m;++i)
{
if(b[i].tag==1)
a[b[i].pos]+=b[i].add*b[i].coe%MOD,a[b[i].pos]%=MOD;
}
for(int i=1;i<=n;++i) printf("%lld ",a[i]);
printf("\n");
return 0;
}

最新文章

  1. Quartz作业调度框架及时间表达式的含义和语法
  2. MySQL数据库迁移(转)
  3. iOS高级必备
  4. UI—代理简单使用
  5. 一个Linq
  6. Linux/Unix shell 监控Oracle监听器(monitor listener)
  7. 在emacs里用w3m浏览网页
  8. Xdebug+phpstorm配置
  9. hibernate的get、load的方法的区别,IllegalArgument异常
  10. OptiScroll 公共例子(只修改了滚动条颜色)
  11. 成功为Android系统配上了GNU开发环境
  12. enum 用法
  13. 消息队列mq的原理及实现方法
  14. vue+webpack+element-ui+git
  15. 约会 倍增lca
  16. C语言中字符输入问题
  17. 数据库MySQL 之 索引原理与慢查询优化
  18. iOS 获取设备型号 ip6更新
  19. 几个你所不知道的技巧助你写出更优雅的vue.js代码
  20. Spring Data JPA + layui的前台分页插件layPage实现页面的分页

热门文章

  1. UNP——第四章,TCP套接字编程
  2. Git-stash(暂存)
  3. Python_错误调试2018.3.17【待完善】
  4. 基于Opencv识别,矫正二维码(C++)
  5. Web基础_0x00_Web工作方式
  6. Oracle数据泵的导入和导出
  7. 深度解析:java必须掌握的知识点——类的重用
  8. 交换机通过Loopback Detection检测(设备所在网络环路)
  9. 追踪聚光特效怎么实现,有Vegas就够了
  10. FL studio系列教程(十七):FL Studio走带面板介绍