树上染色-题解(贪心+DP+二分)
树的上色
题意简述
树上有两个黑点,在每个单位时间内,每个黑点可以把自己相邻的一个白点变为黑色,求把整棵树所有点变为黑色的最短时间。
题解
遇到两个点的题的套路,一般是先讨论简化版情况。现在我们来考虑如果只有一个黑点该怎么办
简化版问题
首先因为树是无根树,我们可以将唯一的黑点变成根节点,此时由于需要最短时间,于是就可以保证我们每一次的操作都是往下进行的,即每个节点的子节点之间不会相互影响,只能由这个节点来一个个更新,这启发我们考虑树形DP。具体的,我们设
现在我们考虑求解子树
引理:按照
的大小,从大到小的给每个 从小到达赋权。
说详细点,就是先按
证明:食用贪心的邻项交换法,考虑两个节点
首先对于右边,因为
所以即需证
那么我们就得到了这个简化版问题的解:
写成代码即为:
void solve(int u,int fa){
int sum=0;
f[u]=0;
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(v!=fa&&vis[i]!=1){
solve(v,u);
}
}
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(v!=fa&&vis[i]!=1)b[++sum]=f[v];
}
sort(b+1,b+sum+1);
reverse(b+1,b+sum+1);//为了代码的方便
for(int i=1;i<=sum;i++){
f[u]=max(f[u],b[i]+i);
}
}
扩展到原问题
对于原问题,将两个黑点来看,可以将树拆成两部分进行处理。而拆树的部分一定就在
以单调性再优化
再来审视这个枚举的过程,设总共
显然此时的
实际上,排序的
最终的Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define N 5000005
int head[N],in,n,m,ver[N],list[N],tot=1,nxt[N],ans=1e9,x,y,vis[N],cnt,f[N],b[N],lst[N];
void add(int u,int v){
nxt[++tot]=head[u],ver[head[u]=tot]=v;
}
void dfs(int u,int in){
list[u]=in;
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if((i^1)==in){
continue;
}
dfs(v,i);
}
}
void find(){
int v=y;
while(v!=x){
lst[++cnt]=list[v];
v=ver[list[v]^1];
}
}
void solve(int u,int fa){
int sum=0;
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(v!=fa&&vis[i]!=1){
solve(v,u);
}
}
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(v!=fa&&vis[i]!=1)b[++sum]=f[v];
}
sort(b+1,b+sum+1);
reverse(b+1,b+sum+1);
for(int i=1;i<=sum;i++){
f[u]=max(f[u],b[i]+i);
}
}
int check(int mid){
memset(f,0,sizeof f);
vis[lst[mid]]=vis[lst[mid]^1]=1;
solve(x,0);
solve(y,0);
vis[lst[mid]]=vis[lst[mid]^1]=0;
return f[x]<=f[y];
}
void init(){
cin>>n>>x>>y;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
add(u,v);add(v,u);
}
dfs(x,0);
find();
}
void solve(){
int l=1,r=cnt;
while(l<r){
int mid=l+r>>1;
if(check(mid)){
r=mid;
}
else {
l=mid+1;
}
ans=min(ans,max(f[x],f[y]));
}
check(l);
ans=min(ans,max(f[x],f[y]));
check(--l);
ans=min(ans,max(f[x],f[y]));
cout<<ans;
}
signed main(){
ios::sync_with_stdio(false);
init();
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!