loading

P10789 [NOI2024] 登山

题意

有一棵树,根节点是 \(1\),除根节点外的每个点有信息 \(l_i,r_i,h_i\),设第 \(i\) 个点的深度是 \(d_i\)

初始你在起点 \(s\),每次你可以向该点的一个儿子(“休息”)或该点的 \([l_i,r_i]\) 级父亲(“冲刺”)移动。每到达一个点,你之后“冲刺”到的点的深度必须满足 \(<d_i-h_i\)(深度从 0 开始)。对 \(2\le i\le n\) 求出有多少种方案能成功到达 \(1\) 号点。

\(T\) 组数据,\(T\le 4,n\le10^5\)

分析

显然设 \(dp_i\) 表示起点为 \(i\) 的方案数。先将 \(l_i,r_i,h_i\) 的限制都写成深度的形式,不难发现最小的 \(h_i\) 限制肯定取在新一轮的休息—冲刺中(否则根本掉不了起点),所以 dp 没有后效性。枚举子树里的点 \(j\) 和冲刺到的点 \(k\) 复杂度是三次方的,发现把贡献放到 \(j\) 上更好统计,枚举 \(i,j\),设 \(lim_{i,j}\) 表示 \((i,j)\) 链上 \(h_i\) 的最小值,那么能取到的 \(k\) 一定满足 \(d_k\in[l_j,\min(r_j,lim_{i,j})]\),是一条祖孙链,可以直接前缀和维护,复杂度 \(O(n^2)\)

考虑进一步优化。前缀和显然可以写成 \(s_{\min(r_j,lim_{i,j})}-s_{l_j-1}\),还是考虑枚举 \(j\),显然只要满足 \(lim_{i,j}\ge l_j\) 的所有 \(i\) 都能得到 \(-s_{l_j-1}\) 的贡献,还是一条祖孙链。对于 \(s_{\min(r_j,lim_{i,j})}\),分类讨论哪个更小,若 \(r_i\) 更小,那么和 \(s_{l_j-1}\) 的处理是同理的;若 \(lim_{i,j}\) 更小,发现不是很好处理,考虑此时不枚举 \(j\) 改为枚举使 \(lim_{i,j}\) 最小的点 \(p\),并钦定其为后缀严格最小值(即深度比他大的点没有和他相等的)。此时合法的 \(i\) 显然也是一条祖孙链,新建一颗重构树,钦定点 \(i\) 的父亲是其在原树上深度最大的 \(h_i\) 比该点小的祖先,那么合法的 \(j\) 是重构树的一条祖孙链。什么祖孙链都可以用倍增+树上差分+树状数组维护,复杂度 \(O(Tn\log n)\)

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<array>
#include<tuple>
#include<ctime>
#include<random>
#include<cassert>
#include<chrono>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0)
#define OTIE cout.tie(0)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
	int qwqx=0,qwqf=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
	if(qwqx<0){qwqx=-qwqx;putchar('-');}
	int qwqy=0;static char qwqz[40];
	while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
	while(qwqy--){putchar(qwqz[qwqy]);}if(ch)putchar(ch);
}
bool Mbg;
const int mod=998244353;
template<typename T1,typename T2>inline void adder(T1 &x,T2 y){x+=y,x=x>=mod?x-mod:x;}
template<typename T1,typename T2>inline void suber(T1 &x,T2 y){x-=y,x=x<0?x+mod:x;}
const int maxn=1e5+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int ID;
int n;
int fa[maxn];
vector<int>G[maxn];
int lft[maxn],rht[maxn],lim[maxn];
int dep[maxn];
int dfn[maxn],dfncnt,siz[maxn];
void dfs0(int x){
	dfn[x]=++dfncnt,siz[x]=1;
	for(int u:G[x]){
		dep[u]=dep[x]+1;
		int l=dep[u]-rht[u],r=dep[u]-lft[u];
		lft[u]=l,rht[u]=r,lim[u]=dep[u]-lim[u]-1;
		dfs0(u),siz[x]+=siz[u];
	}
}
int f[maxn][20],g[maxn][20];
void dfs1(int x,int y){
	f[x][0]=y,g[x][0]=lim[y];
	rep(i,1,16)f[x][i]=f[f[x][i-1]][i-1],g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
	for(int u:G[x])dfs1(u,x);
}
int kthfa(int x,int k){
	int p=x;
	per(i,16,0)if((k>>i)&1)p=f[p][i];
	return p;
}
vector<array<int,3>>vec[maxn];
vector<pii>ad[maxn];
int c[maxn];
int pa[maxn],pas[maxn];
vector<int>T[maxn];
int ff[maxn][20],gg[maxn][20];
void dfs2(int x,int y){
	ff[x][0]=y,gg[x][0]=lim[y];
	rep(i,1,16)ff[x][i]=ff[ff[x][i-1]][i-1],gg[x][i]=min(gg[x][i-1],gg[ff[x][i-1]][i-1]);
	for(int u:T[x])dfs2(u,x);
}
void dfs3(int x){
	for(int u:T[x])dfs3(u),c[x]+=c[u];
}
struct BIT{
	int c[maxn];
	void init(){rep(i,1,n)c[i]=0;}
	void add(int x,int y){while(x<=n)adder(c[x],y),x+=lowbit(x);}
	int qry(int x){int res=0;while(x)adder(res,c[x]),x-=lowbit(x);return res;}
	int qry(int l,int r){return (qry(r)-qry(l-1)+mod)%mod;}
} ds;
int dp[maxn],sum[maxn];
void dfs(int x){
	for(auto i:vec[x]){
		int up=i[0],dn=i[1],fir=i[2];
		if(dep[up]>dep[dn])continue;
		if(up!=1)ds.add(dfn[fa[up]],1ll*sum[x]*(mod-fir)%mod);
		ds.add(dfn[dn],1ll*sum[x]*fir%mod);
	}
	for(int u:G[x]){
		dp[u]=ds.qry(dfn[u],dfn[u]+siz[u]-1);
		sum[u]=(sum[x]+dp[u])%mod;
		dfs(u);
	}
}
void init();
inline void solve_the_problem(){
	n=rd(),init();
	rep(i,2,n){
		fa[i]=rd();lft[i]=rd(),rht[i]=rd(),lim[i]=rd();
		G[fa[i]].pb(i);
	}
	dep[1]=0,lft[1]=rht[1]=lim[1]=lft[0]=rht[0]=lim[0]=-1;
	dfs0(1);
//	rep(i,2,n)write(lft[i],32),write(rht[i],32),write(lim[i]);
	dfs1(1,0);
	rep(i,2,n){
		if(lim[i]<lft[i])continue;
		if(lim[i]>=lft[i]){
			int p=i;
			per(j,16,0)if(g[p][j]>=lft[i])p=f[p][j];
//			printf("add %d %d %d -1\n",kthfa(i,dep[i]-lft[i]+1),p,i);
			vec[kthfa(i,dep[i]-lft[i]+1)].push_back({p,i,mod-1});
		}
		if(lim[i]>=rht[i]){
			int p=i;
			per(j,16,0)if(g[p][j]>=rht[i])p=f[p][j];
//			printf("add %d %d %d 1\n",kthfa(i,dep[i]-rht[i]),p,i);
			vec[kthfa(i,dep[i]-rht[i])].push_back({p,i,1});
		}
	}
	rep(i,1,n){
		int p=i,val=lim[i];
		per(j,16,0)if(g[p][j]>=val)p=f[p][j];
		pa[i]=fa[p],pas[i]=p;
		T[pa[i]].pb(i);
	}
//	rep(i,1,n)write(pa[i],32);P__;
	dfs2(0,0);
	rep(i,2,n){
		if(lim[i]<lft[i])continue;
		int up=i,dn=i;
		if(lim[i]>=rht[i]){
			per(j,16,0)if(gg[dn][j]>=rht[i])dn=ff[dn][j];
			dn=pa[dn];
		}
		if(lim[i]>=lft[i]){
			per(j,16,0)if(gg[up][j]>=lft[i])up=ff[up][j];
		}
		if(dep[up]>dep[dn])continue;
//		printf("c add %d %d %d\n",i,up,dn);
		c[pa[up]]--,c[dn]++;
	}
	dfs3(1);
//	rep(i,1,n)write(c[i],32);P__;
	rep(i,2,n)if(c[i]){
//		printf("add %d %d %d %d\n",kthfa(i,dep[i]-lim[i]),pa[i],i,c[i]);
		vec[kthfa(i,dep[i]-lim[i])].push_back({pas[i],i,c[i]});
	}
	ds.init();
	dp[1]=sum[1]=1;
	dfs(1);
	rep(i,2,n)write(dp[i],i==n?10:32);
}
void init(){
	dfncnt=0;
	rep(i,0,n)G[i].clear(),vec[i].clear(),ad[i].clear(),T[i].clear(),c[i]=0;
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	ID=rd();int _=rd();
	while(_--)solve_the_problem();
}
/*
0 1
6
1 1 1 0
2 1 2 0
3 1 3 2
4 1 4 1
5 1 5 3
*/

posted @ 2025-08-29 22:02  dcytrl  阅读(30)  评论(1)    收藏  举报