洛谷P3267 侦察守卫
时间复杂度:
以前整理的比较笼统
首先,我做的时候设的是
转移
但这显然不对
这是因为我没考虑清楚一些东西:
-
关键点与普通点的区别
-
覆盖会有一大部分是重叠的,别的点帮忙没考虑
先看第二个点
对于别的点帮忙,只需要考虑儿子对父亲的
为啥?
因为儿子对儿子的和父亲对儿子的很好处理,只需要在转移中不累加而是取
那还有对祖先的呢,这样就不能单纯 -1 了吧
对,所以加一维
对于儿子给父亲覆盖完了的点,父亲就不用覆盖了,这需要在状态里扣掉
于是设
关于第一点,我们可以不覆盖普通点
转化一下,如果这个点覆盖的点全是普通点,那么这个点覆不覆盖也没啥影响,这题算的是花费,我们直接把他的花费刨除掉,就是
但是,他可以转移成 0,但如果要用它去覆盖其他点,他的花费是要算的,于是
想转移时要把所有情况都列出来
-
我覆盖我,我的儿子被我覆盖
-
我被我的儿子覆盖
万事俱备!江东纵火团!放箭转移!
前面的好理解,第二个就是
注意这里其实
所以,转移是要先更新
代码很史
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+5;
const int inf=9e18;
int n,d,val[N],head[N<<1],cnt;
bool vis[N];
struct node{int to,nxt;}e[N<<1];
void add(int u,int v){
e[++cnt].nxt=head[u];
head[u]=cnt;
e[cnt].to=v;
}
int f[N][22],g[N][22];
void dfs(int u,int fa){
if(vis[u])f[u][0]=g[u][0]=val[u];
else f[u][0]=g[u][0]=0;
for(int i=1;i<=d;i++)f[u][i]=val[u];
f[u][d+1]=inf;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
for(int j=d;j>=0;j--)f[u][j]=min(f[u][j]+g[v][j],f[v][j+1]+g[u][j+1]);
for(int j=d;j>=0;j--)f[u][j]=min(f[u][j],f[u][j+1]);
g[u][0]=f[u][0];
for(int j=1;j<=d;j++)g[u][j]+=g[v][j-1];
for(int j=1;j<=d;j++)g[u][j]=min(g[u][j],g[u][j-1]);
}
}
signed main(){
cin>>n>>d;
for(int i=1;i<=n;i++){
cin>>val[i];
}
int m;
cin>>m;
for(int i=1;i<=m;i++){
int x;
cin>>x;
vis[x]=1;
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs(1,0);
cout<<f[1][0];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】