长链剖分
长链剖分
顾名思义就是以深度最大的儿子为长儿子做的剖分。
主要思想在于使用指针,使得同一条长链上的 dp 值共用,以达到优化空间复杂度为 ,以及优化时间复杂度。但是前提是 dp 状态中有深度这一维。
上一个例题具体分析一下。
题目大意:给定一棵以 为根的 个节点的树。现在对于每个点,求出一个最小的 使得 最大。其中 表示以 为根的子树中,距离 为 的节点数。
题解
长链剖分板子题。设 表示 。容易得到转移式:
发现 枚举的范围是要到深度层的,且dp状态中有深度,可以使用长链剖分。
剖分部分和重链剖分是一样的,不多赘述。我们暴力合并轻儿子的dp,然后考虑直接继承长儿子。这个我们用指针为每个长链分配内存,让 指向 ,也就是 的dp数组上 的位置,这样就可以达到 的空间复杂度。
发现我们只是暴力合并了长链,长链的深度和为 ,那么时间复杂度也是 的。
参考代码:
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具