题解 P3554 【[POI2013]LUK-Triumphal arch】
又是一道没看任何提示(包括标签)一遍过的dp题,写篇题解纪念一下。
首先看出
其次,B 一定不会走回头路。因为走回头路就说明 B 的某一次选择不是所有选择中最优的,那 B 为啥不在那次选择时就采取最优策略呢?走回头路只会多给 A 染色的机会,那 B 的胜算就更小了。
既然 B 不会走回头路,那么当 B 走到结点
那未雨绸缪的时机又该如何确定呢?假设在 B 走到结点
令
二分的复杂度为
代码如下(给个赞再走吧QAQ,谢谢您!):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define fo(i,x,y) for(int i=x;i<=y;++i)
#define go(i,x,y) for(int i=x;i>=y;--i)
using namespace std;
inline int read(){ int x=0,fh=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') fh=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } return x*fh; }
const int N=3e5+5;
struct Edge{
int to,next;
}e[N<<1];
int f[N],n,head[N],tot,k,son[N];
void connect(int x,int y){
e[++tot]=(Edge){y,head[x]};
head[x]=tot;
}
void _dfs(int now,int from){
for(int i=head[now];i;i=e[i].next){
int p=e[i].to;
if(p==from) continue;
son[now]++;
_dfs(p,now);
}
}
void dfs(int now,int from){
f[now]=son[now]-k;
for(int i=head[now];i;i=e[i].next){
int p=e[i].to;
if(p==from) continue;
dfs(p,now);
if(f[p]>0) f[now]+=f[p];
}
}
int main(){
cin>>n;
fo(i,1,n-1){
int x=read(),y=read();
connect(x,y);
connect(y,x);
}
_dfs(1,0);
int L=son[1],R=0,ans;
fo(i,1,n) R=max(R,son[i]);
while(L<=R){
k=(L+R)>>1;
dfs(1,0);
if(f[1]<=0) R=k-1,ans=k;
else L=k+1;
}
cout<<ans;
return 0;
}
/*
-------------------------------------------------
*/