长链剖分

长链剖分

顾名思义就是以深度最大的儿子为长儿子做的剖分。

主要思想在于使用指针,使得同一条长链上的 dp 值共用,以达到优化空间复杂度为 O(n) ,以及优化时间复杂度。但是前提是 dp 状态中有深度这一维。

上一个例题具体分析一下。

CF1009F Dominant Indices

题目大意:给定一棵以 1 为根的 n 个节点的树。现在对于每个点,求出一个最小的k 使得 d(u,k) 最大。其中 d(u,x) 表示以 u 为根的子树中,距离 ux 的节点数。

1n106

题解

长链剖分板子题。设 f[u][i] 表示 d(u,v) 。容易得到转移式:

f[u][0]=1f[u][i]+=f[v][i1](vson[u])

发现 i 枚举的范围是要到深度层的,且dp状态中有深度,可以使用长链剖分。

剖分部分和重链剖分是一样的,不多赘述。我们暴力合并轻儿子的dp,然后考虑直接继承长儿子。这个我们用指针为每个长链分配内存,让 f[son[u] ] 指向 f[u]+1 ,也就是 u 的dp数组上 d(u,1) 的位置,这样就可以达到 O(n) 的空间复杂度。

发现我们只是暴力合并了长链,长链的深度和为 n ,那么时间复杂度也是 O(n) 的。

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define db double
#define filein(a) freopen(#a".in","r",stdin)
#define fileot(a) freopen(#a".out","w",stdout)
#define sky fflush(stdout)
#define gc getchar
#define pc putchar
namespace IO{
	template<class T>
	inline void read(T &s){
		s=0;char ch=gc();bool f=0;
		while(ch<'0'||'9'<ch) {if(ch=='-') f=1;ch=gc();}
		while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=gc();}
		if(ch=='.'){
			db p=0.1;ch=gc();
			while('0'<=ch&&ch<='9') {s=s+p*(ch^48);ch=gc();}
		}
		s=f?-s:s;
	}
	template<class T,class ...A>
	inline void read(T &s,A &...a){
		read(s);read(a...);
	}
	inline bool blank(char c){
		return c==' ' or c=='\t' or c=='\n' or c=='\r' or c==EOF;
	}
	inline void gs(std::string &s){
		s+='#';char c=gc();
		while(blank(c) ) c=gc();
		while(!blank(c) ){
			s+=c;c=gc();
		}
	}
};
using IO::read;
using IO::gs;
const int N=1e6+3;
int n;
int head[N],nxt[N<<1];
struct Edge{
	int u,v;
}to[N<<1];
int Etot;
inline void link(int u,int v){
	nxt[++Etot]=head[u];
	head[u]=Etot;
	to[Etot]={u,v};
}
inline void _link1(int u,int v){
	link(u,v);link(v,u);
}
int dep[N],son[N];
int buf[N],*dp[N],*now;
void dfs1(int u,int f){
	for(int i=head[u];~i;i=nxt[i]){
		int v=to[i].v;
		if(v==f) continue;
		dfs1(v,u);
		if(dep[v]>dep[son[u] ]){
			son[u]=v;
		}
	}
	dep[u]=dep[son[u] ]+1;
}
int ans[N];
void dfs2(int u,int f){
	dp[u][0]=1;
	if(son[u]){
		dp[son[u] ]=dp[u]+1;
		//其儿子的答案指向其深度为1的答案
		dfs2(son[u],u);
		ans[u]=ans[son[u] ]+1;
	}
	for(int i=head[u];~i;i=nxt[i]){
		int v=to[i].v;
		if(v==f or v==son[u]) continue;
		dp[v]=now;now+=dep[v];
		dfs2(v,u);
		for(int i=1;i<=dep[v];++i){
			dp[u][i]+=dp[v][i-1];
			if(dp[u][i]>dp[u][ans[u] ]){
				ans[u]=i;
			}else if(dp[u][i]==dp[u][ans[u] ] and i<ans[u]){
				ans[u]=i;
			}
		}
	}
	if(dp[u][ans[u] ]==1){
		ans[u]=0;
	}
}
int main(){
	filein(a);fileot(a);
	read(n);
	memset(head,-1,sizeof(head) );
	for(int i=1;i<n;++i){
		int u,v;
		read(u,v);
		_link1(u,v);
	}
	dfs1(1,1);
	now=buf;
	dp[1]=now;now+=dep[1];
	dfs2(1,1);
	for(int i=1;i<=n;++i){
		printf("%d\n",ans[i]);
	}
	return 0;
}

例题

[POI2014]HOT-Hotels

posted @   cbdsopa  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示