思路:
我們可以對於每個 \(i\) 找到它能跳到的最遠的點和最近的點,倍增求一下 \(k\) 級祖先即可,令 \([l_i,r_i]\) 新表示 \(i\) 能跳到其祖先中深度在 \([l_i,r_i]\) 內的點;同時令 \(lim_i = d_i - h_i-1\) 表示 \(i\) 至少要跳到 \(lim_i\) 的深度。
考慮動態規劃演算法,令 \(dp_i\) 表示從 \(i\) 出發到山頂的合法登山序列個數。
那麼相當於先從 \(i\) 滑落到 \(j\),然後再從 \(j\) 衝刺到 \(k\),再加上 \(dp_k\) 的方案數。
則狀態轉移方程為:
其中 \(W(i,j)\) 表示 \(i \to j\) 路徑上 \(lim_k\) 的最小值,因為每次衝刺到達的深度必須小於所有經過的點的 \(lim_k\)。
樸素實現是 \(O(N^3)\) 的,考慮最佳化;注意到 \(k\) 是 \(i\) 的祖先中一段深度連續的點,則我們可以做一個深度的 \(dp_i\) 的字首和,差分即可,時間複雜度最佳化至 \(O(N^2)\),可以得到 25pts。
$O(N^2)$ Code:
namespace Sub1{
ll L,R,x,a,b;
ll s[N],dp[N],dep[N];
void dfs1(ll u){
for(auto v:E[u]){
if(v==fa[u])
continue;
dep[v]=dep[u]+1;
dfs1(v);
}
}
ll get(ll l,ll r){
if(!l)
return s[r];
return (s[r]-s[l-1]+mod)%mod;
}
void dfs3(ll u,ll Min,ll from){
L=l[u],R=min(r[u],Min);
if(L<=R)
dp[from]=(dp[from]+get(L,R))%mod;
for(auto v:E[u]){
if(v==fa[u])
continue;
dfs3(v,min(Min,h[v]),from);
}
}
void dfs2(ll u){
if(dep[u])
s[dep[u]]=(s[dep[u]-1]+dp[u])%mod;
else
s[dep[u]]=dp[u];
for(auto v:E[u]){
if(v==fa[u])
continue;
dfs3(v,h[v],v);
dfs2(v);
}
}
void solve(){
Read();
dfs1(1);
dp[1]=1;
For(i,2,n){
dp[i]=0;
x=i;
h[i]=dep[i]-h[i]-1;
while(r[i]){
x=fa[x];
l[i]--,r[i]--;
if(!l[i])
b=x;
if(!r[i])
a=x;
}
l[i]=dep[a],r[i]=dep[b];
}
dfs2(1);
For(i,2,n){
write(dp[i]);
putchar(' ');
}
putchar('\n');
}
void work(){
while(T--)
solve();
}
};
設 \(u^k\) 表示 \(u\) 的 \(k\) 級祖先,
現在考慮 \(l_j=r_j\) 的特殊性質,注意到對於 \(i\) 子樹內的點 \(j\),它最多隻會對 \(dp_i\) 造成 \(dp_{j^{l_j}}\) 的貢獻,注意到當 \(W(i,j) < r_j\) 時是沒有貢獻的。
則我們考慮列舉 \(j\),且注意到隨著 \(i\) 的深度的變小 \(W(i,j)\) 也會變小,考慮求出 \(g_j\) 表示深度最小的使得 \(W(g_j,j) \ge r_j\) 的點,直接倍增求即可。
那麼對於 \(j \to g_j\) 路徑上的 \(i\) 點,是可以由 \(i\) 下滑到 \(j\) 後衝刺到 \(j^{l_j}\) 的,那麼對於 \(j \to g_j\) 路徑上的 \(dp_i\) 的值都會增加 \(dp_{j^{l_j}}\)。
按照 \(j^{l_j}\) 的深度從小到大依次處理即可。
需要維護路徑加,單點查,可以直接樹剖與樹狀陣列或線段樹,時間複雜度為 \(O(N \log^2 N)\),這樣我們就拿到了 45pts。
$O(N \log^2 N)$ Code:
class Tree{
public:
ll cnt=0;
ll p[N],t[N],z[N],d[N],fa[N];
struct Node{
ll l,r;
ll data;
ll tag;
}X[N<<2];
void dfs1(ll u,ll f){
p[u]=1;
for(auto v:E[u]){
if(v==f)
continue;
d[v]=d[u]+1;
fa[v]=u;
dfs1(v,u);
p[u]+=p[v];
if(p[v]>p[z[u]])
z[u]=v;
}
}
void dfs2(ll u,ll k){
dfn[u]=++cnt;
t[u]=k;
if(!z[u])
return ;
dfs2(z[u],k);
for(auto v:E[u]){
if(v==fa[u]||v==z[u])
continue;
dfs2(v,v);
}
}
void build(ll k,ll l,ll r){
X[k].l=l,X[k].r=r;
X[k].data=X[k].tag=0;
if(l==r)
return ;
ll mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void add(ll k,ll v){
X[k].data=Add(X[k].data,v);
X[k].tag=Add(X[k].tag,v);
}
void push_down(ll k){
if(X[k].tag){
add(k<<1,X[k].tag);
add(k<<1|1,X[k].tag);
X[k].tag=0;
}
}
void update(ll k,ll l,ll r,ll v){
if(X[k].l==l&&r==X[k].r){
add(k,v);
return ;
}
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(r<=mid)
update(k<<1,l,r,v);
else if(l>mid)
update(k<<1|1,l,r,v);
else{
update(k<<1,l,mid,v);
update(k<<1|1,mid+1,r,v);
}
}
ll query(ll k,ll i){
if(X[k].l==i&&i==X[k].r)
return X[k].data;
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(i<=mid)
return query(k<<1,i);
else
return query(k<<1|1,i);
}
void update(ll u,ll v,ll h){
while(t[u]!=t[v]){
if(d[t[u]]<d[t[v]])
swap(u,v);
update(1,dfn[t[u]],dfn[u],h);
u=fa[t[u]];
}
if(d[u]>d[v])
swap(u,v);
update(1,dfn[u],dfn[v],h);
}
void init(){
For(i,1,n)
z[i]=0;
cnt=0;
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
}
}Tr;
namespace Sub2{
ll x,cnt;
ll g[N],dep[N],Fa[N][M],F[N][M];
vector<pi> G[N];
void dfs1(ll u){
For(j,1,M-1)
Fa[u][j]=Fa[Fa[u][j-1]][j-1];
for(auto v:E[u]){
if(v==fa[u])
continue;
dep[v]=dep[u]+1;
Fa[v][0]=u;
dfs1(v);
}
}
ll get_fa(ll u,ll k){
if(!k)
return u;
_For(j,0,M-1){
if(k>=(1ll<<j)){
k-=(1ll<<j);
u=Fa[u][j];
}
}
return u;
}
void dfs2(ll u){
For(j,1,M-1)
F[u][j]=min(F[u][j-1],F[Fa[u][j-1]][j-1]);
for(auto v:E[u]){
if(v==fa[u])
continue;
F[v][0]=h[v];
dfs2(v);
}
}
void solve(){
cnt=0;
Read();
Tr.init();
For(j,0,M-1)
Fa[1][j]=1;
dfs1(1);
For(i,0,n-1)
G[i].clear();
For(i,2,n){
x=get_fa(i,l[i]);
l[i]=r[i]=dep[x];
h[i]=dep[i]-h[i]-1;
G[l[i]].push_back({i,x});
}
For(j,0,M-1)
F[1][j]=INF;
dfs2(1);
For(i,2,n){
x=i;
_For(j,0,M-1)
if(r[i]<=F[x][j])
x=Fa[x][j];
g[i]=dep[x]+1;
if(g[i]<=dep[i])
g[i]=get_fa(i,dep[i]-g[i]);
else
g[i]=-1;
}
Tr.update(1,1,1);
For(i,0,n-1){
if(G[i].empty())
continue;
for(auto t:G[i]){
ll v=t.fi;
if(g[v]==-1)
continue;
Tr.update(v,g[v],Tr.query(1,dfn[t.se]));
}
}
For(i,2,n){
write(Tr.query(1,dfn[i]));
putchar(' ');
}
putchar('\n');
}
void work(){
while(T--)
solve();
}
};
現在考慮根據 \(l_j=r_j\) 的思路,求 \(l_j \ne r_j\) 的情況。
還是一樣,列舉 \(j\),則對於一個 \(i\) 會增加 \(s_{\min(r_j,W(i,j))}-s_{l_j-1}\) 的貢獻,其中 \(s_u\) 在 \(j\) 的祖先鏈上,表示深度為 \(1 \sim u\) 的點的 \(dp\) 值。
考慮分開計算,發現對於 \(-s_{l_j-1}\) 的部分,就是 \(l_j=r_j\) 的情況,倍增求出深度最小的點 \(i\) 使得 \(W(i,j) \ge l_j\),然後對於 \(i \to j\) 路徑上的點都增加 \(-s_{l_j-1}\) 的貢獻。
現在是如何處理 \(s_{\min(r_j,W(i,j))}\) 的部分,注意到肯定還是先取一段 \(r_j\),同樣列舉 \(j\),倍增找到深度最小的滿足 \(W(i,j) > r_j\)(注意是 \(>\)) 的 \(i\),則對於 \(j \to i\) 路徑上的 \(dp\) 值,都要增加 \(s_{r_j}\)。
然後考慮處理 \(s_{W(i,j)}\) 的情況,考慮列舉 \(u\),使得 \(lim_u\) 是 \(i \to j\) 的嚴格字尾最小值(即最小值中深度最深的那個點),注意到我們只需要求出 \(u\) 子樹內有多少個 \(j\) 滿足 \(u \to j\) 的路徑中沒有小於等於 \(lim_u\) 的 \(lim_k\),且 \(lim_u \in [l_j,r_j]\)。
只要求出了這樣的 \(j\) 的個數 \(sum\),則可以倍增求出深度最小的 \(i\) 使得 \(W(i,u) = lim_u\),那麼直接對於 \(i \to u\) 的路徑上的點,都會增加 \(s_{lim_u} \times sum\) 的貢獻。
注意到這樣操作會有先後順序的問題,考慮再求出 \(s_x\) 時,才考慮 \(l_j-1=x\) 和 \(r_j = x\) 和 \(lim_u=x\) 的貢獻。
該部分暴力 Code:
namespace Sub3{
ll Min,sum,x,a,b,c,t;
ll dep[N],dp[N],g1[N],g2[N],g3[N];
ll Fa[N][M];
vector<pi> E1[N],E2[N],E3[N];
void dfs(ll u){
For(j,1,M-1)
Fa[u][j]=Fa[Fa[u][j-1]][j-1];
for(auto v:E[u]){
if(v==fa[u])
continue;
Fa[v][0]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
ll get_fa(ll u,ll k){
if(!k)
return u;
_For(j,0,M-1){
if(k>=(1ll<<j)){
k-=(1ll<<j);
u=Fa[u][j];
}
}
return u;
}
ll get_sum(ll u){
ll ans=0;
while(u){
ans=Add(ans,dp[u]);
u=fa[u];
}
return ans;
}
void dfs2(ll u,ll k){
if(h[u]<=h[k]&&u!=k)
return ;
if(l[u]<=h[k]&&h[k]<=r[u])
sum++;
for(auto v:E[u]){
if(v==fa[u])
continue;
dfs2(v,k);
}
}
void solve(){
Read();
dfs(1);
dp[1]=1;
For(i,0,n-1){
E1[i].clear();
E2[i].clear();
E3[i].clear();
}
For(i,2,n){
dp[i]=0;
x=i;
t=h[i]+1;
h[i]=dep[i]-h[i]-1;
while(l[i]>=1||r[i]>=1||t>=1){
x=fa[x];
l[i]--,r[i]--,t--;
if(!l[i])
b=x;
if(!r[i])
a=x;
if(!t)
c=x;
}
l[i]=dep[a],r[i]=dep[b];
if(l[i])
E1[l[i]-1].push_back({i,fa[a]});
E2[r[i]].push_back({i,b});
E3[h[i]].push_back({i,c});
}
//cerr<<'\n';
For(i,2,n){
if(l[i]){
Min=INF;
x=i,a=-1;
while(fa[x]!=1){
Min=min(Min,h[x]);
if(Min<l[i])
break;
a=x;
x=fa[x];
}
g1[i]=a;
}
else
g1[i]=-1;
Min=INF;
x=i,a=-1;
while(fa[x]!=1){
Min=min(Min,h[x]);
if(Min<=r[i])
break;
a=x;
x=fa[x];
}
g2[i]=a;
x=i;
while(fa[x]!=1){
if(h[fa[x]]<h[i])
break;
x=fa[x];
}
g3[i]=x;
//cerr<<i<<':'<<g1[i]<<','<<g2[i]<<','<<g3[i]<<'\n';
}
//cerr<<'\n';
For(i,0,n-1){
for(auto t:E1[i]){
x=t.fi,a=get_sum(t.se),b=g1[x];
if(b==-1)
continue;
//cerr<<"("<<x<<"->"<<b<<")-"<<a<<'\n';
while(x!=fa[b]){
dp[x]=(dp[x]-a+mod)%mod;
x=fa[x];
}
}
for(auto t:E2[i]){
x=t.fi,a=get_sum(t.se),b=g2[x];
if(b==-1)
continue;
//cerr<<"("<<x<<"->"<<b<<")+"<<a<<'\n';
while(x!=fa[b]){
dp[x]=Add(dp[x],a);
x=fa[x];
}
}
for(auto t:E3[i]){
x=t.fi,a=get_sum(t.se),b=g3[x];
if(b==-1)
continue;
sum=0;
dfs2(x,x);
//cerr<<"("<<x<<"->"<<b<<")+"<<sum<<'*'<<a<<'\n';
while(x!=fa[b]){
dp[x]=(dp[x]+sum*a%mod)%mod;
x=fa[x];
}
}
}
For(i,2,n){
write(dp[i]);
putchar(' ');
}
putchar('\n');
}
void work(){
while(T--)
solve();
}
};
這樣的話操作都是一些基本操作,鏈加,鏈查,倍增最佳化等,唯一需要注意的是查詢 \(u\) 子樹內有多少個 \(j\) 滿足 \(u \to j\) 的路徑中沒有小於等於 \(lim_u\) 的 \(lim_k\),且 \(lim_u \in [l_j,r_j]\)。
考慮對於 \(i\) 找到 \(i \to 1\) 的路徑上第一個滿足 \(lim_j < lim_i\) 的 \(j\),那麼令 \(Fa_i = j\)。
根據這個 \(Fa\),建出邊為 \(i \to Fa_i\) 的新樹,那麼上述詢問就變為了在求新樹中 \(u\) 子樹內的點 \(j\) 滿足 \(lim_u \in [l_j,r_j]\) 的個數,證明顯然,不再闡述。
那麼可以每次將 \([l_j,r_j]\) 範圍內的 \(sum_i\) 增加 \(1\),那麼滿足條件的數的數量就是 \(sum_{lim_u}\)。
考慮對於新樹求出 dfn 序,則 \(u\) 子樹內的點可以算作一段區間 \([L,R]\),然後建出字首主席樹即可快速求 \(lim_u\) 被區間包含的個數(因為要區間加,可以直接標記永久化)。
也可以使用 dsu on tree 做,但是本人太菜不會。
總時間複雜度為 \(O(N \log^2 N)\)。
注意主席樹的空間要開 \(50\) 倍。
完整程式碼;
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const ll N=1e5+10,M=20,mod=998244353,INF=1e9;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
int T,n;
int root[N],fa[N],l[N],r[N],h[N],id[N],_id[N],dfn[N];
vector<int> E[N],G[N];
inline void add(int u,int v){
E[u].push_back(v);
E[v].push_back(u);
}
inline void ADD(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
inline void Read(){
n=read();
For(i,1,n){
E[i].clear();
G[i].clear();
}
For(i,2,n){
fa[i]=read(),l[i]=read(),r[i]=read(),h[i]=read();
add(fa[i],i);
}
}
class Tree{
public:
int cnt=0;
int p[N],t[N],z[N],d[N],fa[N];
struct Node{
int l,r,len;
ll data;
ll tag;
}X[N<<2];
inline void dfs1(int u,int f){
p[u]=1;
for(auto v:E[u]){
if(v==f)
continue;
d[v]=d[u]+1;
fa[v]=u;
dfs1(v,u);
p[u]+=p[v];
if(p[v]>p[z[u]])
z[u]=v;
}
}
inline void dfs2(int u,int k){
dfn[u]=++cnt;
t[u]=k;
if(!z[u])
return ;
dfs2(z[u],k);
for(auto v:E[u]){
if(v==fa[u]||v==z[u])
continue;
dfs2(v,v);
}
}
inline void build(int k,int l,int r){
X[k].len=r-l+1;
X[k].l=l,X[k].r=r;
X[k].data=X[k].tag=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline void pushup(int k){
X[k].data=Add(X[k<<1].data,X[k<<1|1].data);
}
inline void add(int k,int v){
X[k].data=(X[k].data+1ll*X[k].len*v%mod)%mod;
X[k].tag=Add(X[k].tag,v);
}
inline void push_down(int k){
if(X[k].tag){
add(k<<1,X[k].tag);
add(k<<1|1,X[k].tag);
X[k].tag=0;
}
}
inline void update(int k,int l,int r,int v){
if(X[k].l==l&&r==X[k].r){
add(k,v);
return ;
}
push_down(k);
int mid=(X[k].l+X[k].r)>>1;
if(r<=mid)
update(k<<1,l,r,v);
else if(l>mid)
update(k<<1|1,l,r,v);
else{
update(k<<1,l,mid,v);
update(k<<1|1,mid+1,r,v);
}
pushup(k);
}
inline int query(int k,int l,int r){
if(X[k].l==l&&r==X[k].r)
return X[k].data;
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(r<=mid)
return query(k<<1,l,r);
else if(l>mid)
return query(k<<1|1,l,r);
else
return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%mod;
}
inline int query(int k,int i){
if(X[k].l==i&&i==X[k].r)
return X[k].data;
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(i<=mid)
return query(k<<1,i);
else
return query(k<<1|1,i);
}
inline void update(int u,int v,int h){
while(t[u]!=t[v]){
if(d[t[u]]<d[t[v]])
swap(u,v);
update(1,dfn[t[u]],dfn[u],h);
u=fa[t[u]];
}
if(d[u]>d[v])
swap(u,v);
update(1,dfn[u],dfn[v],h);
}
inline int ask(int u,int v){
int ans=0;
while(t[u]!=t[v]){
if(d[t[u]]<d[t[v]])
swap(u,v);
ans=(ans+query(1,dfn[t[u]],dfn[u]))%mod;
u=fa[t[u]];
}
if(d[u]>d[v])
swap(u,v);
ans=(ans+query(1,dfn[u],dfn[v]))%mod;
return ans;
}
inline void init(){
For(i,1,n)
z[i]=0;
cnt=0;
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
}
}Tr;
namespace Seg{
int siz[N];
int cnt,s;
struct Node{
int L,R;
int tag;
}X[N*50];
inline void dfs(int u,int fa){
id[u]=++s;
_id[s]=u;
siz[u]=1;
for(auto v:G[u]){
if(v==fa)
continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
inline void tidy(){
For(i,1,cnt)
X[i]={0,0,0};
s=cnt=0;
dfs(1,1);
}
inline void build(int &k,int l,int r){
if(!k)
k=++cnt;
X[k].tag=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(X[k].L,l,mid);
build(X[k].R,mid+1,r);
}
inline void update(int &k,int l,int r,int L,int R,int v){
X[++cnt]=X[k];
k=cnt;
if(l==L&&r==R){
X[k].tag=Add(X[k].tag,v);
return ;
}
ll mid=(l+r)>>1;
if(R<=mid)
update(X[k].L,l,mid,L,R,v);
else if(L>mid)
update(X[k].R,mid+1,r,L,R,v);
else{
update(X[k].L,l,mid,L,mid,v);
update(X[k].R,mid+1,r,mid+1,R,v);
}
}
inline void Ask(int k,int l,int r,int i,int &ans){
ans=Add(ans,X[k].tag);
if(l==i&&i==r)
return ;
int mid=(l+r)>>1;
if(i<=mid)
Ask(X[k].L,l,mid,i,ans);
else
Ask(X[k].R,mid+1,r,i,ans);
}
inline int Ask(int u){
int X=0,Y=0;
Ask(root[id[u]+siz[u]-1],0,n,h[u],X);
Ask(root[id[u]-1],0,n,h[u],Y);
return (X-Y+mod)%mod;
}
};
namespace Std{
int Min,sum,x,a,b,c,t;
int dep[N],g1[N],g2[N],g3[N];
int Fa[N][M],F[N][M];
vector<pi> E1[N],E2[N],E3[N];
inline void dfs(int u){
For(j,1,M-1)
Fa[u][j]=Fa[Fa[u][j-1]][j-1];
for(auto v:E[u]){
if(v==fa[u])
continue;
Fa[v][0]=u;
dep[v]=dep[u]+1;
dfs(v);
}
}
inline int get_fa(int u,int k){
if(!k)
return u;
_For(j,0,M-1){
if(k>=(1ll<<j)){
k-=(1ll<<j);
u=Fa[u][j];
}
}
return u;
}
inline void dfs1(int u){
For(i,1,M-1)
F[u][i]=min(F[u][i-1],F[Fa[u][i-1]][i-1]);
for(auto v:E[u]){
if(v==fa[u])
continue;
F[v][0]=h[v];
dfs1(v);
}
}
inline void solve(){
Read();
For(j,0,M-1)
Fa[1][j]=1;
dfs(1);
For(i,1,n)
root[i]=0;
For(i,0,n-1){
E1[i].clear();
E2[i].clear();
E3[i].clear();
}
For(i,2,n){
a=get_fa(i,r[i]),b=get_fa(i,l[i]),c=get_fa(i,h[i]+1);
h[i]=dep[i]-h[i]-1;
l[i]=dep[a],r[i]=dep[b];
if(l[i])
E1[l[i]-1].push_back({i,fa[a]});
E2[r[i]].push_back({i,b});
E3[h[i]].push_back({i,c});
}
For(j,0,M-1)
F[1][j]=INF;
dfs1(1);
For(i,2,n){
if(l[i]){
x=i;
_For(j,0,M-1)
if(F[x][j]>=l[i])
x=Fa[x][j];
if(x==i)
g1[i]=-1;
else
g1[i]=get_fa(i,dep[i]-dep[x]-1);
}
else
g1[i]=-1;
x=i;
_For(j,0,M-1)
if(F[x][j]>r[i])
x=Fa[x][j];
if(x==i)
g2[i]=-1;
else
g2[i]=get_fa(i,dep[i]-dep[x]-1);
Min=INF,x=i;
_For(j,0,M-1)
if(F[x][j]>=h[i])
x=Fa[x][j];
ADD(i,x);
if(x==i)
g3[i]=-1;
else
g3[i]=get_fa(i,dep[i]-dep[x]-1);
}
Tr.init();
Tr.update(1,1,1);
Seg::tidy();
Seg::build(root[1],0,n);
For(i,2,n){
root[i]=root[i-1];
Seg::update(root[i],0,n,l[_id[i]],r[_id[i]],1);
a=0;
Seg::Ask(root[i],0,n,0,a);
}
For(i,0,n-1){
for(auto t:E1[i]){
x=t.fi,b=g1[x];
if(b==-1)
continue;
a=Tr.ask(1,t.se);
Tr.update(x,b,mod-a);
}
for(auto t:E2[i]){
x=t.fi,b=g2[x];
if(b==-1)
continue;
a=Tr.ask(1,t.se);
Tr.update(x,b,a);
}
for(auto t:E3[i]){
x=t.fi,b=g3[x];
if(b==-1)
continue;
a=Tr.ask(1,t.se);
sum=Seg::Ask(x);
Tr.update(x,b,1ll*sum*a%mod);
}
}
For(i,2,n){
write(Tr.query(1,dfn[i]));
putchar(' ');
}
putchar('\n');
}
inline void work(){
while(T--)
solve();
}
};
int main(){
//open("A.in","A.out");
read(),T=read();
Std::work();
return 0;
}