换根dp 学习笔记
换根dp:树形dp的一类
题目大意:给定一个 \(n\) 个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和最大。
一个显然的 \(n^2\) 暴力:以每个点为根 分别跑一遍dfs暴力统计 也显然会 T 飞
我们可以先以1为根 dfs一遍求出答案 考虑如何从以1为根时的答案推出所有点的答案
然后我们可以发现 如果把1的儿子移上来 儿子子树内的所有点dep都 -1 而其它点dep++
(可以自己画一画体会一下)
可以得到转移:\(f_y=f_x-siz_y+(n-siz_y),y\in son_x\)
每次换根的时候 我们发现原子树内的其它点 \(siz\) 不变
那么再进行一次dfs 直接转移即可 时间复杂度 \(O(n)\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=2e6+5;
const int M=8e2+5;
const int inf=0x7fffffff;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'|c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writel(int x){write(x);pc('\n');}
inl void writei(int x){write(x);pc(' ');}
inl void debug1(int x){pc('?');write(x);pc('\n');}
inl void debug2(int x){pc('#');write(x);pc('\n');}
int n,u,v,siz[N],dep[N],f[N],ma,ans;
int head[N],nxt[N],to[N],cnt;
inl void add(int u,int v){
nxt[++cnt]=head[u];
to[cnt]=v;
head[u]=cnt;
}
inl void dfs1(int x,int fa){
siz[x]=1;dep[x]=dep[fa]+1;f[1]+=dep[x];
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa)continue;
dfs1(y,x);
siz[x]+=siz[y];
}
}
inl void dfs2(int x,int fa){
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa)continue;
f[y]=f[x]+n-(siz[y]<<1);
dfs2(y,x);
}
}
signed main(){
n=read();
for(int i=1;i<=n-1;i++){
u=read();v=read();
add(u,v);add(v,u);
}
dep[0]=-1;dfs1(1,0);dfs2(1,0);
for(int i=1;i<=n;i++)
if(f[i]>ma)ans=i,ma=f[i];
writel(ans);
return 0;
}
ybtoj 树形dp I.周年纪念日 \(/\) P2986 [USACO10MAR] Great Cow Gathering G
(ybt得先求个最小生成树 其他都一样)
其实和上一道题差不多 每次换根每条边的贡献从1变成了边权 子树大小由点数变点权和 其他都一样
记得开long long ( long long max是 \(0x7 + 15\) 个 $f\ $ 少打一个 \(f\) 调好久()
其它点减少数量是 点权和 $-siz_y\ $ 不是 \(n-siz_y\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define int ll
#define gc getchar
#define pc putchar
const int N=2e6+5;
const int M=8e2+5;
const int inf=0x7fffffffffffffff;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'|c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writel(int x){write(x);pc('\n');}
inl void writei(int x){write(x);pc(' ');}
inl void debug1(int x){pc('?');write(x);pc('\n');}
inl void debug2(int x){pc('#');write(x);pc('\n');}
int n,u,v,c,siz[N],f[N],p[N],mi=inf,ans,tot;
int head[N],nxt[N],to[N],w[N],cnt;
inl void add(int u,int v,int c){
nxt[++cnt]=head[u];
to[cnt]=v;w[cnt]=c;
head[u]=cnt;
}
inl void dfs1(int x,int fa){
siz[x]=p[x];
for(int i=head[x];i;i=nxt[i]){
int y=to[i],c=w[i];
if(y==fa)continue;
dfs1(y,x);
siz[x]+=siz[y];
f[1]+=siz[y]*c;
}
}
inl void dfs2(int x,int fa){
for(int i=head[x];i;i=nxt[i]){
int y=to[i],c=w[i];
if(y==fa)continue;
f[y]=f[x]+(tot-(siz[y]<<1))*c;
dfs2(y,x);
}
}
signed main(){
n=read();
for(int i=1;i<=n;i++)p[i]=read(),tot+=p[i];
for(int i=1;i<=n-1;i++){
u=read();v=read();c=read();
add(u,v,c);add(v,u,c);
}
dfs1(1,0);dfs2(1,0);
for(int i=1;i<=n;i++)
if(f[i]<mi)ans=i,mi=f[i];
writel(mi);
return 0;
}

浙公网安备 33010602011771号