这场 abc F、G 质量堪忧。怎么能扔板子上来呢?
Solution
这种每次修改对后面询问有影响,又每次都要输出答案的,离线就基本做不了了,这时候就往动态算法想,其实做过几道 ddp 的题就看出来这是个板子。
由于题目中的式子性质优良,我们很明显可以把它写成矩阵的形式。
我们预处理轻儿子的乘积和,即 \(g_{u}=\prod\limits_{v\in son,v\ne Hson}f_v\) ,然后问题中的式子就可以写成这个矩阵:
\[\begin{bmatrix} f_{son} & 1 \\ \end{bmatrix} \times \begin{bmatrix} g_{now} & 0\\ a_{now} & 1\\ \end{bmatrix}= \begin{bmatrix} f_{now} & 1 \\ \end{bmatrix}\]然后因为不方便转移,要从后往前乘,我们改造一下就变成:
\[\begin{bmatrix} g_{now} & a_{now}\\ 0 & 1\\ \end{bmatrix} \times \begin{bmatrix} f_{son} \\ 1 \end{bmatrix}= \begin{bmatrix} f_{now} \\ 1 \end{bmatrix} \]初始矩阵是 \(\begin{bmatrix}0 \\ 1\end{bmatrix}\)。
这样就可以从根节点往下乘了。
然后之后操作修改就是模板了,撤销操作用逆元即可。
然后这题一个小麻烦的地方就来了。因为这题有 \(0\) ,然后 \(0\) 没有逆元,所以要进行一些适当的处理即可,这个地方我选择的使用一个数组记录下轻儿子 \(0\) 的个数,\(g\) 数组不乘 \(0\)。
然后就是 ddp 的一些细节了。
使用的是树剖的写法,\(w=2\) 是矩阵大小,还有个求逆元,时间复杂度 \(O(q\log^2 n\times w^3+q\log n\log mod)\) 。
因为笔者的习惯,代码中 \(f\) 代表上述的 \(g\) 数组,代码中的 \(g\) 数组代表矩阵。
Code
#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
const int mod=998244353;
ll inv(ll a,ll x=mod-2)
{
ll res=1;
while(x)
{
if(x&1) res=res*a%mod;
a=a*a%mod;
x>>=1;
}
return res;
}
int n;
int head[N],tot=1;
int a[N];
struct edge{
int to,next;
}e[N*2];
void add(int u,int v)
{
e[tot]=(edge){v,head[u]};
head[u]=tot++;
}
ll f[N],w[N];
struct node{
int r[2][2];
int n,m;
}g[N],oo,zero;
node operator * (node a,node b)
{
node c;
c.n=a.n,c.m=b.m;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
c.r[i][j]=0;
for(int k=0;k<2;k++)
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
c.r[i][j]=(c.r[i][j]+(1ll*a.r[i][k]*b.r[k][j]%mod))%mod;
return c;
}
int pos[N];
struct segtree{
node tr[N*4];
void modify(int l,int r,int p,int x)
{
if(l==r)
{
tr[x]=g[pos[p]];
return;
}
int mid=(l+r)/2;
if(p<=mid) modify(l,mid,p,x*2);
else modify(mid+1,r,p,x*2+1);
tr[x]=tr[x*2]*tr[x*2+1];
}
node query(int l,int r,int L,int R,int x)
{
if(l>R||r<L) return oo;
if(l>=L&&r<=R) return tr[x];
int mid=(l+r)/2;
node lv=query(l,mid,L,R,x*2),rv=query(mid+1,r,L,R,x*2+1);
if(lv.n==-1) return rv;
if(rv.n==-1) return lv;
return lv*rv;
}
}tr;
int fa[N],dep[N],siz[N],Son[N];
int ed[N],id[N],ids,top[N];
int tag[N];
void dfs1(int now,int f)
{
fa[now]=f;
dep[now]=dep[f]+1;
siz[now]=1;
int maxx=0;
for(int i=head[now];i;i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs1(v,now);
siz[now]+=siz[v];
if(siz[v]>maxx) maxx=siz[v],Son[now]=v;
}
}
void dfs2(int now,int topf)
{
++ids;
id[now]=ids;
pos[ids]=now;
ed[topf]=id[now];
top[now]=topf;
if(Son[now]) dfs2(Son[now],topf),w[now]=w[Son[now]];
f[now]=1;
for(int i=head[now];i;i=e[i].next)
{
int son=e[i].to;
if(son==fa[now]||son==Son[now]) continue;
dfs2(son,son);
w[now]=w[now]*w[son]%mod;
if(!w[son]) tag[now]++;
else f[now]=f[now]*w[son]%mod;
}
w[now]+=a[now],w[now]%=mod;
g[now].n=g[now].m=2;
g[now].r[0][0]=f[now],g[now].r[0][1]=a[now],
g[now].r[1][0]=0,g[now].r[1][1]=1;
if(tag[now]) g[now].r[0][0]=0;
tr.modify(1,n,id[now],1);
}
void updata(int x,ll v)
{
g[x].r[0][1]=v;
while(x)
{
ll last=tr.query(1,n,id[top[x]],ed[top[x]],1).r[0][1];
tr.modify(1,n,id[x],1);
ll now=tr.query(1,n,id[top[x]],ed[top[x]],1).r[0][1];
x=fa[top[x]];
if(!last) tag[x]--;
else f[x]=f[x]*inv(last)%mod;
if(!now) tag[x]++;
else f[x]=f[x]*now%mod;
if(tag[x]) g[x].r[0][0]=0;
else g[x].r[0][0]=f[x];
}
}
int q;
int main()
{
oo.n=-1;
zero.n=zero.m=2;
zero.r[1][1]=1;
scanf("%d%d",&n,&q);
for(int i=2;i<=n;i++)
{
int x;
scanf("%d",&x);
add(x,i);
}
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dfs1(1,0);
dfs2(1,1);
while(q--)
{
int v,x;
scanf("%d%d",&x,&v);
updata(x,v);
printf("%d\n",tr.query(1,n,1,ed[1],1).r[0][1]);
}
return 0;
}
标签:int,题解,ll,son,bmatrix,mod,now,abc351g
From: https://www.cnblogs.com/g1ove/p/18163780