#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define inf 1000000000
#define infll 1000000000000000000ll
#define pii pair<int,int>
#define rep(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
#define per(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
#define F(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define dF(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define cmh(sjy) while(sjy--)
#define lowbit(x) (x&(-x))
#define HH printf("\n")
#define eb emplace_back
#define poly vector<int>
#define SZ(x) ((int)x.size()
using namespace std;
// 快速取模幂运算
template<typename T>inline void chkmax(T &x,const T &y){ x=std::max(x,y); }
template<typename T>inline void chkmin(T &x,const T &y){ x=std::min(x,y); }
const int mod=998244353, maxn=100005;
void fre(){
freopen("mountain.in","r",stdin),freopen("mountain.out","w",stdout);
}
// 快速幂函数
inline int qpow(int x,ll y){
int rt=1;
for(;y;y>>=1,x=1ll*x*x%mod)
if(y&1) rt=1ll*rt*x%mod;
return rt;
}
// 加法、减法、乘法的封装,带模数处理
inline void inc(int &x,const int y){ x=(x+y>=mod)?(x+y-mod):(x+y); }
inline void dec(int &x,const int y){ x=(x>=y)?(x-y):(x+mod-y); }
inline void mul(int &x,const int y){ x=1ll*x*y%mod; }
inline int add(const int x,const int y){ return (x+y>=mod)?(x+y-mod):(x+y); }
inline int sub(const int x,const int y){ return (x>=y)?(x-y):(x+mod-y); }
inline int prod(const int x,const int y){ return 1ll*x*y%mod; }
int n, dfn[maxn], siz[maxn], tim, stk[maxn], top, dep[maxn], f[maxn], fa[maxn];
int anc[maxn][20], mn[maxn][20]; // 倍增祖先数组
int ul[maxn], ur[maxn], uh[maxn], lim[maxn], pre[maxn], fr[maxn], tol[maxn], tor[maxn], diff[maxn], th[maxn];
vector<int>g[maxn], tmp, nxt[maxn]; // 子树结构
vector<pii>qu[maxn]; // 查询队列
// 第一次DFS:预处理树结构、深度、倍增表等
void dfs1(int u){
dfn[u]=++tim, siz[u]=1;
stk[top++]=u;
tmp.push_back(u);
// 找到某个祖先节点 v,满足其限制条件
auto find=[&](int k){ return k>dep[u]?0:stk[dep[u]-k]; };
int v=u;
dF(i,18,0)
if(anc[v][i]&&mn[v][i]>=lim[u])
v=anc[v][i];
fr[u]=fa[v], nxt[fr[u]].push_back(u);
// 处理冲刺区间 [l_i, r_i]
const int L=dep[u]-ul[u]+1, R=dep[u]-ur[u];
// 获取当前节点的“休息目标”
th[u]=find(uh[u]+1);
if(lim[u]>=R){
int p=u,to=find(ur[u]+1);
dF(i,18,0)
if(anc[p][i]&&mn[p][i]>=R)p=anc[p][i];
qu[to].push_back(mkp(u,mod-1)), qu[to].push_back(mkp(fa[p],1));
inc(diff[fa[p]],mod-1);
}else inc(diff[u],mod-1);
if(lim[u]>=L){
int p=u,to=find(ul[u]);
dF(i,18,0)
if(anc[p][i]&&mn[p][i]>=L)p=anc[p][i];
qu[to].push_back(mkp(u,1)), qu[to].push_back(mkp(fa[p],mod-1));
inc(diff[fa[p]],1);
}else inc(diff[u],1);
// 遍历子树
for(int v:g[u])dfs1(v),siz[u]+=siz[v];
--top;
}
// 第三次DFS:进行差分标记合并
void dfs3(int u){
for(int v:nxt[u])dfs3(v),inc(diff[u],diff[v]);
if(!u)return;
qu[th[u]].push_back(mkp(u,diff[u]));
qu[th[u]].push_back(mkp(fr[u],sub(0,diff[u])));
}
// 树状数组实现前缀和查询
namespace DS{
int t[maxn];
void init(){ memset(t,0,sizeof t); }
void add(int x,int y){ if(x)for(;x<=n;x+=lowbit(x))inc(t[x],y); }
int query(int x){ int R=0;for(;x;x^=lowbit(x))inc(R,t[x]);return R; }
int query(int l,int r){ return l>r?0:sub(query(r),query(l-1)); }
}
// 第二次DFS:最终DP计算
void dfs2(int u){
f[u]=(u==1)?1:DS::query(dfn[u],dfn[u]+siz[u]-1);
pre[u]=add(pre[fa[u]],f[u]);
// 将查询结果更新进树状数组
for(auto [x,y]:qu[u])DS::add(dfn[x],1ll*y*pre[u]%mod);
// 遍历子树
for(int v:g[u])dfs2(v);
}
// 主处理函数:读入数据并调用各部分
void solve(){
cin>>n, tim=top=0, dep[0]=-1;
F(i,0,n) g[i].clear(), fr[i]=diff[i]=0, qu[i].clear(), nxt[i].clear();
F(i,2,n) cin>>fa[i]>>ul[i]>>ur[i]>>uh[i], dep[i]=dep[fa[i]]+1, lim[i]=dep[i]-uh[i]-1;
// 构建图结构
F(i,2,n) g[fa[i]].push_back(i);
// 倍增表预处理
F(i,1,n) anc[i][0]=fa[i], mn[i][0]=lim[fa[i]];
F(j,1,18) F(i,1,n) anc[i][j]=anc[anc[i][j-1]][j-1], mn[i][j]=min(mn[i][j-1], mn[anc[i][j-1]][j-1]);
// DFS遍历
dfs1(1), dfs3(0);
DS::init();
// DP计算
dfs2(1);
// 输出答案
F(i,2,n) cout<<f[i]<<' ';
cout<<endl;
}
int testid;
// 主函数
signed main(){
fre(), ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int zsy=1; cin>>testid>>zsy;
F(____,1,zsy)solve(); // 多组测试数据循环
}
这份代码请给dfs1里面再添加一些注释
最新发布