zixiangzhan @ 2021-09-19 23:00:10
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define LL long long
#define il inline
#define re register
il int read()
{
int s=0,w=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') w=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
s=(s<<1)+(s<<3)+c-'0';
c=getchar();
}
return s*w;
}
il LL read_ll()
{
LL s=0,w=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') w=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
s=(s<<1)+(s<<3)+c-'0';
c=getchar();
}
return s*w;
}
const int N=100010;
const int M=1000010;
const LL mod=998244353;
int n,m,Q,op,rt;
LL a[N];
LL ad[N],mul[N],cnt[N];
int pos[N];
int zhan[N],n_zh;
int head1[N],ver1[M],nxt1[M],tot1,ru1[N];
int head2[N],ver2[M],nxt2[M],tot2,ru2[N];
queue<int> q;
/*
NOTE
ad:"add",对应某一1操作的V值
mul:multiply,即调用这个函数后整个序列变成原来的几倍
cnt:某一函数被调用多少次
要建立超级节点
pos:1操作的P ,即1操作对应得下标
"1""2"分别表示topo1,topo2使用的图,即分别为
反图/正图对应的变量
(雀食十分别扭)
*/
il void kkk1(int u,int v)
{
ver1[++tot1]=v;
nxt1[tot1]=head1[u];
head1[u]=tot1;
}
il void kkk2(int u,int v)
{
ver2[++tot2]=v;
nxt2[tot2]=head2[u];
head2[u]=tot2;
}
il void topo1()
{
while(!q.empty()) q.pop();
for(re int i=1;i<=rt;i++){
if(ru1[i]==0) q.push(i);//!
}
while(q.size()){
int xx=q.front();
q.pop();
for(re int i=head1[xx];i;i=nxt1[i]){
int vv=ver1[i];
mul[vv]=(mul[vv]*mul[xx])%mod;
//跑反图的过程就相当于dfs回溯了,所以其实
//记忆化搜索也行
ru1[vv]--;
if(ru1[vv]==0) q.push(vv);
}
}
}
il void topo2()
{//正图反着跑可还行……
while(!q.empty()) q.pop();
for(re int i=1;i<=rt;i++){
if(!ru2[i]) q.push(i);
}
while(q.size()){
int xx=q.front();
q.pop();
LL now_mul=1LL;
//当前函数内的乘法标记
for(re int i=head2[xx];i;i=nxt2[i]){
/*这里注意要倒序遍历,因为每个函数执行完之后
只影响在它前面执行的函数,而由于链表特性,
正着挨个插进去之后,后插入的正好就在前面
虽然这里考不考虑对结果没有影响,但是应该
考虑这个问题*/
int vv=ver2[i];
cnt[vv]=(cnt[vv]+cnt[xx]*now_mul)%mod;
now_mul=(now_mul*mul[vv])%mod;
ru2[vv]--;
if(ru2[vv]==0) q.push(vv);
}
}
return;
}
signed main()
{
freopen("P7077_20.in","r",stdin);
freopen("lz_P7077.out","w",stdout);
n=read();
for(re int i=1;i<=n;i++) a[i]=read_ll();
m=read();
rt=m+1;//超级根节点,找点的时候一定不要忘了把超级根节点也
//考虑到!!!
mul[rt]=1,cnt[rt]=1;
for(re int i=1;i<=m;i++){
op=read();
if(op==1){
pos[i]=read(),ad[i]=read(),mul[i]=1;
}
else if(op==2) mul[i]=read_ll();
else if(op==3){
mul[i]=1;
ru1[i]=read();
for(re int j=1;j<=ru1[i];j++){
int vv=read();
kkk2(i,vv);
ru2[vv]++;
zhan[++n_zh]=vv;
}
while(n_zh){
kkk1(zhan[n_zh],i);
zhan[n_zh--]=0;
}
}
}
Q=read();
for(re int i=1;i<=Q;i++){
int vv=read();
kkk2(rt,vv);
ru2[vv]++;
zhan[++n_zh]=vv;
}
ru1[rt]=Q;
while(n_zh){
kkk1(zhan[n_zh],rt);
zhan[n_zh--]=0;
}
topo1();//第一遍跑反图
topo2();//第二遍跑正图
for(re int i=1;i<=n;i++) a[i]=(a[i]*mul[rt])%mod;
//因为每一次乘法操作都对原始序列有影响,而topo2并没
//有进行这个操作
for(re int i=1;i<=m;i++){
if(ad[i]!=0) a[pos[i]]=(a[pos[i]] + (cnt[i]*ad[i]%mod))%mod;
}
for(re int i=1;i<=n;i++){
printf("%lld ",((a[i]%mod)+mod)%mod);
}
return 0;
}
by zixiangzhan @ 2021-09-19 23:01:00
最后一个点WA掉了,而且差的很离谱
by peiwenjun @ 2021-09-29 11:16:42
数组开大一点,比如把M调成2e6,我自己开1e6的数组也是莫名其妙TLE(O2下WA),然后开成2e6就A了
by zixiangzhan @ 2021-10-01 22:42:39
@peiwenjun 真的欸!谢谢您(数组真是个玄学的东西
by peiwenjun @ 2021-10-02 08:40:27
不用谢