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;
}
posted @ 2020-10-19 21:58  Creed-qwq  阅读(95)  评论(0编辑  收藏  举报