P3942 将军令
Pro:https://www.luogu.com.cn/problem/P3942
Sol:
时隔多年重新学会了这道题目的正确做法
首先我们可以得到这样一个显然的贪心就是
每次找到一个深度最深的没被覆盖的点
然后找到他的K级祖先
然后把他K级祖先周围距离不超过K的点全部覆盖
正确性显然
但这样做的复杂度是和K有关系的
考虑一个类似DP的方法
对于每一个节点x
去计算\(f[x],g[x]\)两个数组
F表示X的子树内没有被控制的最远点的距离
G表示X的子树内已经选择的点最近点的距离
考虑怎么递推
\[\begin{align*}
& \ \ F_x=max(F_{to})+1
\\
& \ \ G_x=min(G_{to})+1
\\
F_x+G_x<=k时:& \ \ F_x=-inf
\\
F_x==k时:& \ \ F_x=-inf,G_x=0,ans++
\end{align*}
\]
再注意特判一下根节点的情况就可以了。。。。
下面时写的很好的一篇题解
\(\\\\\\\)
#include<bits/stdc++.h>
#define N 550000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
struct edge{int to,nxt;}e[N*2];
int num,head[N];
inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
int n,k,ans,f[N],g[N];
void dfs(int x,int fa)
{
f[x]=0;g[x]=+inf;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa)continue;
dfs(to,x);
f[x]=max(f[x],f[to]+1);
g[x]=min(g[x],g[to]+1);
}
if(f[x]+g[x]<=k)f[x]=-inf;
if((x==1&&f[x]>=0)||(f[x]==k))f[x]=-inf,g[x]=0,ans++;
}
int main()
{
n=read();k=read();read();
num=-1;memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
dfs(1,1);printf("%d",ans);
return 0;
}