题解 P5439 【【XR-2】永恒】
Owen_codeisking · · 题解
如果没有
首先看到这题一眼边分治 + 虚树上
算了,老老实实算贡献吧。
我们对于每个点对
不妨令
因为三个东西乘起来不好处理,我们把
第一个部分的贡献是可以离线处理的,时间复杂度
当然,第一个部分的贡献我们多算了,我们要在第二部分减掉。
第二个部分的贡献就暴力多了,假设
时间复杂度
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int maxn=300000+10;
const int mod=998244353;
int n,m,rt,a[maxn],fa[maxn],siz[maxn],ans,head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
namespace Tree
{
int c[2][maxn],w[maxn],val[maxn],head[maxn],to[maxn],nxt[maxn],tot;
int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn],id[maxn],mp[maxn],tim;
#define lowbit(x) ((x)&(-(x)))
inline void add(int *c,int x,int y)
{
for(;x<=m;x+=lowbit(x)) c[x]=(c[x]+y)%mod;
}
inline int Ask(int *c,int x)
{
int ans=0;
for(;x;x-=lowbit(x)) ans=(ans+c[x])%mod;
return ans;
}
inline void Update(int x,int v) {add(c[0],x,v);add(c[1],x,1ll*(x-1)*v%mod);}
inline void update(int l,int r,int v) {Update(l,v);Update(r+1,mod-v);}
inline int Query(int x) {return (1ll*x*Ask(c[0],x)%mod-Ask(c[1],x)+mod)%mod;}
inline int query(int l,int r) {return (Query(r)-Query(l-1)+mod)%mod;}
inline void modify(int x,int y)
{
for(;x;x=fa[top[x]]) update(id[top[x]],id[x],y);
}
inline int ask(int x)
{
int ans=0;
for(;x;x=fa[top[x]]) ans=(ans+query(id[top[x]],id[x]))%mod;
return ans;
}
inline int ask_pre(int x)
{
int ans=0;
for(;x;x=fa[top[x]]) ans=(ans+(val[id[x]]-val[id[top[x]]-1]+mod)%mod)%mod;
return ans;
}
inline void addedge(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int f)
{
siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
int maxson=-1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
dfs1(y,x);siz[x]+=siz[y];w[x]=(w[x]+w[y])%mod;
if(siz[y]>maxson) maxson=siz[y],son[x]=y;
}
}
void dfs2(int x,int topf)
{
id[x]=++tim;mp[tim]=x;top[x]=topf;
if(son[x]) dfs2(son[x],topf);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==son[x]) continue;
dfs2(y,y);
}
}
inline void init()
{
scanf("%d",&fa[1]);
for(int i=2;i<=m;i++) scanf("%d",&fa[i]),addedge(fa[i],i);
scanf("%*s");
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) w[a[i]]=(w[a[i]]+::siz[i])%mod;
for(int i=head[1];i;i=nxt[i]) dfs1(to[i],0),dfs2(to[i],to[i]);
for(int i=1;i<=m;i++) val[i]=w[mp[i]];
for(int i=1;i<=m;i++) val[i]=(val[i]+val[i-1])%mod;
}
}
inline void addedge(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x)
{
siz[x]=1;
for(int i=head[x];i;i=nxt[i]) dfs(to[i]),siz[x]+=siz[to[i]];
}
void dfs1(int x)
{
ans=(ans+1ll*Tree::ask(a[x])*siz[x]%mod)%mod;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
Tree::modify(a[x],(n-siz[y]-siz[x]+mod)%mod);
dfs1(y);
Tree::modify(a[x],(siz[y]+siz[x]-n+mod)%mod);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&fa[i]);
if(!fa[i]) rt=i;
else addedge(fa[i],i);
}
dfs(rt);Tree::init();
for(int i=1;i<=n;i++)
{
ans=(ans+1ll*Tree::ask_pre(a[i])*siz[i]%mod)%mod;
ans=(ans+1ll*siz[i]*siz[i]%mod*(mod-Tree::dep[a[i]])%mod)%mod;
}
ans=1ll*ans*((mod+1)>>1)%mod;dfs1(rt);
printf("%d\n",ans);
return 0;
}