← 返回题解列表

P1064 A 病毒 官方题解

【题意简述】

在一棵有根树上统计从每个非根节点出发、满足历史防疫限制并最终到达根的感染路线数。

【正解】

fxf_x 表示从 xx 出发的合法路线数,f1=1f_1=1;令

pre(v)=upath(1,v)fu.pre(v)=\sum_{u\in path(1,v)}f_u.

固定起点 xx,枚举子树内节点 yy,表示先只向下扩散到 yy,再第一次向上感染。沿 xyx\to y 维护

U(x,y)=minvpath(x,y)(dvhv1).U(x,y)=\min_{v\in path(x,y)}(d_v-h_v-1).

yy 上跳后的落点深度范围为

L=dyry,R=min(dyly,U(x,y)).L=d_y-r_y,\qquad R=\min(d_y-l_y,U(x,y)).

LRL\le R,贡献是对应祖先路径上的 t=LRfanc(y,t)\sum_{t=L}^{R}f_{\operatorname{anc}(y,t)},用 prepre 的路径前缀差在 O(1)\mathcal O(1) 时间求出。对 xx 的整棵子树求和即得 fxf_x

【正确性】

每条合法路线都存在唯一的“第一次向上感染”位置 yy。上式精确枚举其所有合法落点;防疫限制由路径最小值 U(x,y)U(x,y) 同时约束,故不会遗漏或重复。由于第一次上跳一定到达 xx 的严格祖先,按编号递增计算时所需状态均已求出。

【复杂度】

时间复杂度 O(n2)\mathcal O(n^2),空间复杂度 O(n)\mathcal O(n)

【参考代码】

/*Author:EhundateghDate:2026/8/17Name:cancer.cppYou steal,I kill.*/#include <vector>#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 2010using namespace std;const int Mod=998244353;inline int Add(int a,int b){return a+b>=Mod?a+b-Mod:a+b;}inline int Del(int a,int b){return a-b<0?a-b+Mod:a-b;}int c,T,n,Fa[MAXN],Depth[MAXN],l[MAXN],r[MAXN],h[MAXN];int Dp[MAXN],Pre[MAXN],Path[MAXN],Ans;vector <int> Son[MAXN]; void DFS(int Now,int Limit){    Path[Depth[Now]]=Now;    Limit=min(Limit,Depth[Now]-h[Now]-1);    int Left=Depth[Now]-r[Now];    int Right=min(Depth[Now]-l[Now],Limit);    if(Left<=Right){        int Temp=Pre[Path[Right]];        if(Left) Temp=Del(Temp,Pre[Path[Left-1]]);        Ans=Add(Ans,Temp);    }    for(int i=0;i<(int)Son[Now].size();i++) DFS(Son[Now][i],Limit);} void Solve(){    scanf("%d",&n);    for(int i=1;i<=n;i++) Son[i].clear();    Depth[1]=0;Dp[1]=Pre[1]=1;    for(int i=2;i<=n;i++){        scanf("%d%d%d%d",&Fa[i],&l[i],&r[i],&h[i]);        Depth[i]=Depth[Fa[i]]+1;        Son[Fa[i]].push_back(i);    }    for(int i=2;i<=n;i++){        int Now=i;        while(Now){Path[Depth[Now]]=Now;Now=Fa[Now];}        Ans=0;DFS(i,n);        Dp[i]=Ans;        Pre[i]=Add(Pre[Fa[i]],Dp[i]);    }    for(int i=2;i<=n;i++) printf("%d%c",Dp[i]," \n"[i==n]);} int main(){    scanf("%d%d",&c,&T);    while(T-->0) Solve();    return 0;}