题解:P8294 [省选联考 2022] 最大权独立集问题
居然有个高手
·
2025-03-14 22:59:55
·
题解
超级分讨题吗,哈哈那无敌了。
这种题可以先想一下怎么做多项式复杂度。考虑一个点的度数至多为 3 ,因此我们可以分类讨论一下有关其交换的顺序。我们发现在交换了 x 与 fa_x 之间的边后 x 子树内为独立问题,可以想到记录子树型状态。
那么我们要记录什么样的状态呢?显然我们关心 x 与 fa_x 交换时的值,同时还有 x 的儿子的交换状态。同时我们又发现,若钦定交换时 d_x = i,d_{fa_x}=j ,则在二者交换前,对于 x 子树内,我们只关心让 x 留下的值为 i 时的最小代价;交换后我们只关心 x 目前带的值为 j 时的最小代价。
因此我们可以记录 f_{x,i,0/1/2} 与 g_{x,i,0/1/2} 表示 x 初始时带的权值为 a_i ,进行了 0/1/2 状态的交换操作后子树内的最小代价;g_{x,i,0/1/2} 表示 x 进行了 0/1/2 状态的操作后,最终保留权值为 a_i 时子树内的最小代价。(0 表示只换左子树,1 表示只换右子树,2 表示都换)
显然,f_{x,i,op} 状态有效当且仅当 i=x 或 i 在 x 子树外,g_{x,i,op} 状态有效当且仅当 i 在 x 子树内。
开始分讨转移了。对于 f_{x,i,0} ,我们枚举此时左子树 ls 的交换情况:
未交换:f_{x,i,0}=a_{ls}+a_i+f_{ls,i,2} 。
交换一边(记作 op ):f_{x,i,0}=a_i+\underset j\min\{g_{ls,j,op} + a_j + f_{ls,i,1-op}\} 。
交换两边:f_{x,i,0}=a_i + \underset j \min\{g_{ls,j,2}+a_j\} 。
容易发现上式中 i,j 不同时出现,因此预处理 g_{ls,j,op}+a_j 的最小值即可。
对于 g_{x,i,0} ,我们同样枚举交换情况:
未交换:此时 i=ls ,g_{x,i,0}=a_{ls}+a_x+f_{ls,x,2} 。
交换一边:g_{x,i,0}=a_i + a_x + g_{ls,i,op} + f_{ls,x,1-op} 。
交换两边:g_{x,i,0} = a_i+a_x+g_{ls,i,2} 。
而对于 $f_{x,i,2}$ 我们分讨先交换左子树还是右子树,则对于另一侧子树而言是 $f_{x,i,op}$ 的情况,我们可以仿照上文分讨,并进行适当预处理即可解决。
对于 $g_{x,i,2}$,我们应当考虑其来自哪颗子树,那么自然钦定了左右子树的先后顺序;若其恰好为 $ls$ 或 $rs$ 时则钦定了 $i$ 点的交换顺序,进行上文中大小为 $4$ 的分讨即可(有两种对偶情况,因此文中只呈现 $3$ 种,代码中可以得到完整体现);否则对两侧子树进行大小为 $12$ 的分类讨论。仿照上文稍加讨论即可得到,具体细节可参考代码。
在一切计算中,我们容易发现虽然会出现临时变量 $j$,但其总不与 $i$ 相关,因此我们可以预处理多种 $j$ 相关的计算式最小值,枚举 $i$ 计算时简单调用即可保证复杂度。
最终答案即为 $f_{1,1,2}$,本题在 $O(n^2)$ 的时空复杂度内得到解决。
贴一份代码:
```cpp
#include <bits/stdc++.h>
using namespace std;
const int N=5005;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
long long f[N][N][3],g[N][N][3],mn1[N][3],mn2[N][3],mn3[N][3][3],mn4[N][3],a[N];
int n,dfn[N],ed[N],cnt;
vector<int>e[N];
inline void pre(int x){
dfn[x]=++cnt;
for(auto y : e[x])pre(y);
ed[x]=cnt;
}
inline void dfs(int x){
for(auto y : e[x])dfs(y);
if(e[x].empty()){
for(int i = 1;i<=n;i++)f[x][i][0]=f[x][i][1]=f[x][i][2]=0;
g[x][x][0]=g[x][x][1]=g[x][x][2]=0;
}
if(e[x].size()>=1){
int ls = e[x][0];
for(int i = 1;i<=n;i++){
if(dfn[i]<dfn[ls]||dfn[i]>ed[ls]){
f[x][i][0]=a[i]+a[ls]+f[ls][i][2];
f[x][i][0]=min(f[x][i][0],a[i] + min(mn1[ls][0] + f[ls][i][1],min(mn1[ls][1] + f[ls][i][0],mn1[ls][2])));
}
else if(i==ls)g[x][ls][0]=a[x]+a[ls]+f[ls][x][2];
else{
g[x][i][0]=a[x]+a[i]+min(g[ls][i][0] + f[ls][x][1],min(g[ls][i][1] + f[ls][x][0],g[ls][i][2]));
}
}
}
if(e[x].size()==1){
int ls = e[x][0];
for(int i = 1;i<=n;i++){
if(dfn[i]<dfn[ls]||dfn[i]>ed[ls])f[x][i][2]=f[x][i][0],f[x][i][1]=0;
else g[x][i][2]=g[x][i][0],g[x][i][1]=1e18;
}
}
if(e[x].size()==2){
int ls=e[x][0],rs=e[x][1];
for(int i = 1;i<=n;i++){
if(dfn[i]<dfn[rs]||dfn[i]>ed[rs]){
f[x][i][1]=a[i] + a[rs] + f[rs][i][2];
f[x][i][1]=min(a[i] + min(mn1[rs][0] + f[rs][i][1],min(mn1[rs][1] + f[rs][i][0],mn1[rs][2])),f[x][i][1]);
}
else if(i==rs)g[x][rs][1]=a[x]+a[rs]+f[rs][x][2];
else{
g[x][i][1]=a[x]+a[i]+min(g[rs][i][0] + f[rs][x][1],min(g[rs][i][1] + f[rs][x][0],g[rs][i][2]));
}
}
for(int j = 1;j<=n;j++){
if(dfn[ls]<=dfn[j]&&dfn[j]<=ed[ls]){
for(int k = 0;k<3;k++){
mn2[ls][k]=min(mn2[ls][k],g[ls][j][k]+a[j]+f[x][j][1]);
mn4[ls][k]=min(mn4[ls][k],g[ls][j][k]+a[j]*2);
for(int o = 0;o<3;o++)mn3[ls][k][o]=min(mn3[ls][k][o],g[ls][j][k] + 2*a[j] + f[rs][j][o]);
}
}
else if(dfn[rs]<=dfn[j]&&dfn[j]<=ed[rs]){
for(int k = 0;k<3;k++){
mn2[rs][k]=min(mn2[rs][k],g[rs][j][k]+a[j]+f[x][j][0]);
mn4[rs][k]=min(mn4[rs][k],g[rs][j][k]+a[j]*2);
for(int o = 0;o<3;o++)mn3[rs][k][o]=min(mn3[rs][k][o],g[rs][j][k] + 2*a[j] + f[ls][j][o]);
}
}
}
for(int i = 1;i<=n;i++){
if(dfn[i]<=dfn[x]||dfn[i]>ed[x]){
f[x][i][2] = a[i] + f[ls][i][2] + a[ls] + f[x][ls][1];
f[x][i][2]=min(f[x][i][2],min(a[i] + mn2[ls][0] + f[ls][i][1],a[i] + mn2[ls][1] + f[ls][i][0]));
f[x][i][2]=min(f[x][i][2],a[i] + mn2[ls][2]);
f[x][i][2] = min(f[x][i][2],a[i] + f[rs][i][2] + a[rs] + f[x][rs][0]);
f[x][i][2]=min(f[x][i][2],min(a[i] + mn2[rs][0] + f[rs][i][1],a[i] + mn2[rs][1] + f[rs][i][0]));
f[x][i][2]=min(f[x][i][2],a[i]+mn2[rs][2]);
}
else if(dfn[ls]<=dfn[i]&&dfn[i]<=ed[ls]){
if(i==ls){
g[x][i][2]=a[x] + f[rs][x][2] + a[rs] + f[ls][rs][2] + a[rs] + a[i];
g[x][i][2]=min(g[x][i][2],min(a[x] + mn3[rs][0][2] + f[rs][x][1] + a[i],a[x] + mn3[rs][1][2] + f[rs][x][0] + a[i]));
g[x][i][2]=min(g[x][i][2],mn3[rs][2][2] + a[x] + a[i]);
}
else{
g[x][i][2]=a[x]+a[i]+a[rs]*2+f[rs][x][2]+min(g[ls][i][2],min(g[ls][i][0]+f[ls][rs][1],g[ls][i][1]+f[ls][rs][0]));
g[x][i][2]=min(g[x][i][2],a[x]+a[i]+g[ls][i][2]+min(min(f[rs][x][1]+mn4[rs][0],f[rs][x][0]+mn4[rs][1]),mn4[rs][2]));
g[x][i][2]=min(g[x][i][2],a[x]+a[i]+min(min(mn3[rs][2][0]+g[ls][i][1],mn3[rs][2][1]+g[ls][i][0]),mn4[rs][2]+g[ls][i][2]));
for(int o = 0;o<2;o++)for(int k = 0;k<2;k++)g[x][i][2]=min(g[x][i][2],a[x]+a[i]+f[rs][x][o^1]+mn3[rs][o][k^1]+g[ls][i][k]);
}
}
else{
if(i==rs){
g[x][i][2]=a[x] + f[ls][x][2] + a[ls] + f[rs][ls][2] + a[ls] + a[i];
g[x][i][2]=min(g[x][i][2],min(a[x] + mn3[ls][0][2] + f[ls][x][1] + a[i],a[x] + mn3[ls][1][2] + f[ls][x][0] + a[i]));
g[x][i][2]=min(g[x][i][2],mn3[ls][2][2] + a[x] + a[i]);
}
else{
g[x][i][2]=a[x]+a[i]+a[ls]*2+f[ls][x][2]+min(g[rs][i][2],min(g[rs][i][0]+f[rs][ls][1],g[rs][i][1]+f[rs][ls][0]));
g[x][i][2]=min(g[x][i][2],a[x]+a[i]+g[rs][i][2]+min(min(f[ls][x][1]+mn4[ls][0],f[ls][x][0]+mn4[ls][1]),mn4[ls][2]));
g[x][i][2]=min(g[x][i][2],a[x]+a[i]+min(min(mn3[ls][2][0]+g[rs][i][1],mn3[ls][2][1]+g[rs][i][0]),mn4[ls][2]+g[rs][i][2]));
for(int o = 0;o<2;o++)for(int k = 0;k<2;k++)g[x][i][2]=min(g[x][i][2],a[x]+a[i]+f[ls][x][o^1]+mn3[ls][o][k^1]+g[rs][i][k]);
}
}
}
}
for(int j = 1;j<=n;j++){
if(dfn[x]<=dfn[j]&&dfn[j]<=ed[x]){
for(int o = 0;o<3;o++)mn1[x][o]=min(mn1[x][o],g[x][j][o]+a[j]);
}
}
}
int main(){
n=read();
for(int i = 1;i<=n;i++)a[i]=read();
for(int i = 2;i<=n;i++)e[read()].push_back(i);
pre(1);
memset(f,0x3f,sizeof f);memset(g,0x3f,sizeof g);
memset(mn1,0x3f,sizeof mn1);memset(mn2,0x3f,sizeof mn2);memset(mn3,0x3f,sizeof mn3);memset(mn4,0x3f,sizeof mn4);
dfs(1);
cout<<f[1][1][2];
return 0;
}
```