换根DP
引入
换根DP,又叫二次扫描,是树形DP的一种。
其相比于一般的树形DP具有以下特点:
1.以树上的不同点作为根,其解不同。
2.故为求解答案,不能单求某点的信息,需要求解每个节点的信息。
2.故无法通过一次搜索完成答案的求解,因为一次搜索只能得到一个节点的答案。
经典题
P3478 [POI2008]STA-Station
给定一个n个点的无根树,问以树上哪个节点为根时,其所有节点的深度和最大?
sol:
AC码
int dep[Max],siz[Max],ans[Max];
void dfs(int u,int fa)
{
dep[u]=dep[fa]+1;
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(fa==v) continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
void dfs1(int u,int fa)
{
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(fa==v) continue;
ans[v]=ans[u]-siz[v]+(siz[1]-siz[v]);
dfs1(v,u);
}
}
signed main()
{
n=rd;
pos(i,1,n-1)
{
int x=rd,y=rd;
add(x,y);
add(y,x);
}
dfs(1,0);
pos(i,1,n) ans[1]+=dep[i];
dfs1(1,0);
int res=0,re=0;
pos(i,1,n)
{
if(res<=ans[i])
{
res=ans[i];
re=i;
}
}
printf("%lld\n",re);
return 0;
}
P2986 [USACO10MAR]Great Cow Gathering G
sol:与上题相似
AC码
int dep[Max],siz[Max],ans[Max];
int val[Max];
void dfs(int u,int fa,int d)
{
dep[u]=dep[fa]+d;
siz[u]=val[u];
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa)continue;
dfs(v,u,e[i].l);
siz[u]+=siz[v];
}
}
void dfs1(int u,int fa)
{
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa)continue;
ans[v]=ans[u]+((siz[1]-siz[v])-siz[v])*e[i].l;
dfs1(v,u);
}
}
signed main()
{
n=rd;
pos(i,1,n) val[i]=rd;
pos(i,1,n-1)
{
int x=rd,y=rd,z=rd;
add(x,y,z),add(y,x,z);
}
dfs(1,0,0);
pos(i,1,n) ans[1]+=dep[i]*val[i];
dfs1(1,0);
int res=inf;
pos(i,1,n) res=min(res,ans[i]);
printf("%lld\n",res);
return 0;
}
CF1324F Maximum White Subtree
题目大意:一棵树,节点有黑有白,从某节点出发,遇黑-1,遇白+1。
问:从每个节点出发,能得到的最大值是多少?
sol:
AC码
int n;
int a[Max],f[Max],ans[Max];
vector<int>e[Max];
void dfs(int u,int fa)
{
f[u]=(a[u]==1?1:-1);
for(auto v:e[u])
{
if(v==fa)continue;
dfs(v,u);
f[u]+=max(0,f[v]);
}
}
void dfs1(int u,int fa)
{
for(auto v:e[u])
{
if(fa==v)continue;
ans[v]=max(0,ans[u]-max(0,f[v]))+f[v];
dfs1(v,u);
}
}
int main()
{
n=rd;
pos(i,1,n) a[i]=rd;
pos(i,1,n-1)
{
int x=rd,y=rd;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0);
ans[1]=f[1];
dfs1(1,0);
pos(i,1,n) printf("%d ",ans[i]);
return 0;
}