CF1776M Parmigiana With Seafood 题解

发布时间 2023-07-25 20:57:01作者: L_G_J

先将所有的叶子取 \(\max\) 贡献给答案,以下讨论的所有点中不考虑叶子。

首先可以考虑先手能否删到 \(n\):不难发现当 \(2 \mid n\) 的时候可以,然后我们就排除了一半的 \(n\),于是以下令 \(2 \not \mid n\)。接下来,考虑先手能否删掉 \(n-1\),那么把 \(n-1 \to n\) 的路径当成一个大点,容易发现当 \(2\not \mid \text{dis}_{n-1,n}\) 的时候才能删掉 \(n-1\)。也就相当于对于任意二元组 \((x,y)\) ,满足 \(2\not\mid\text{dis}_{x,y}\)\(\min\{x,y\}\) 必定可以贡献给答案。

由于上面解决了距离为奇数的所有点对,那么以下考虑的点中两两距离为偶数。

容易发现树上两两距离为偶数的点所构成的虚树点的个数必定是奇数。直接做不好入手,不妨直接考虑三个点构成的虚树。那么这相当于共线的三个点或者满足 \(\exist u,2 \mid \text dis_{u,x},2 \mid \text dis_{u,y},2 \mid \text dis_{u,z}\) 或者 \(\exist u,2 \not \mid \text dis_{u,x},2 \not\mid \text dis_{u,y},2 \not\mid \text dis_{u,z}\) 的三元组 \((x,y,z)\)。考虑后面两者,其中后者必定可以取到 \(\min \{u,\max\{x,y,z\}\}\),这在之前已经讨论过,那么现在考虑前者。

发现这个东西的贡献直接就是 \(\min\{x,y,z\}\),这是因为图上除了这个虚树之外的点的个数为偶数,那么由于它有 \(3\) 个叶子,删剩这个虚树以及叶子上挂的 \(3\) 个点的时候删的步数必定是奇数,那么下一步后手必定会暴露出一个叶子,先手直接删掉即可。

进一步,可以发现树上两两距离为偶数的点所构成的虚树必定可以以若干个三元组 \((x,y,z)\) 的形式考虑,那么我们很可能已经考虑了所有可能的答案,接下来只需证明对于所有满足集合内任意两点距离为偶数并且任意三点不构成上面的三元组 \((x,y,z)\) 的点集 \(S\),后手可以拿走里面所有的点即可。

根据上面的分讨,这种情况当且仅当 \(S\) 中的任意三点共线且两两距离为偶数,那么这就相当于一条长度为偶数的一条链上的几个距离为偶数的点,那么结论的正确性就是显然的。

所以现在的答案就是所有的满足前面条件的二元组 \((x,y)\)\(\min\{x,y\}\) 和三元组 \((x,y,z)\)\(\min\{x,y,z\}\) 的最大值。至此,通过二分答案 \(x\) 并单次 \(O(n)\) 判断 \(\geq x\) 的所有点是否可以构成任意一个点集,我们获得了一个 \(O(n \log n)\) 的一个做法,已经可以通过。

但是通过不知道怎么想到地额外发掘一些性质,存在一个线性做法:所有的点集必定形如 \((n,x),(n,x,y),(x,y,z)\) ,其中最后一种满足 \(u=n\)。前两种显然,考虑证明最后一种:如果存在一个不满足条件的三元组 \((x,y,z)\) ,那么一定满足 \((n,x),(n,y),(n,z),(x,y),(y,z),(z,x)\) 这几个点对的距离全部为偶数,简单分讨可知 \((n,x,y)\) 必定也是一个满足条件的点集。

所以直接以 \(n\) 为根进行一次 dfs 即可,复杂度 \(O(n)\)

代码:

const int N=1e5+50;
int n,f[N][2],dep[N],deg[N],head[N],cnt,ans,pos1,pos2; 
struct edge{int to,nxt;}e[N<<1];
vector<pair<int,int> > vec;
inline void addedge(int u,int v){e[++cnt]=(edge){v,head[u]},head[u]=cnt;}
void dfs(int u,int fa,int id)
{
	dep[u]=dep[fa]+1,f[u][0]=(deg[u]>1)?u:0;
	if(dep[u]&1) ans=max(ans,u);
	else if(deg[u]>1) vec.emplace_back(MP(u,id));
	int maxn1=0,maxn2=0;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u,id),f[u][0]=max(f[u][0],f[v][1]),f[u][1]=max(f[u][1],f[v][0]);
		if(f[v][1]>=maxn1) maxn2=maxn1,maxn1=f[v][1];
		else if(f[v][1]>maxn2) maxn2=f[v][1];
	}
	if(!(dep[u]&1)) ans=max(ans,min(maxn1,maxn2));
}
int main(void)
{
	n=read();int u,v;
	fr(i,2,n) u=read(),v=read(),addedge(u,v),addedge(v,u),++deg[u],++deg[v];
	if(!(n&1)) return writeln(n),0;
	fr(i,1,n) if(deg[i]==1) ans=max(ans,i);
	for(int i=head[n];i;i=e[i].nxt) dfs(e[i].to,n,e[i].to);
	sort(vec.begin(),vec.end());int sz=vec.size();
	pfr(i,sz-1,0)
	{
		if(!pos1) pos1=vec[i].sec;
		else if((!pos2)&&vec[i].sec!=pos1) pos2=vec[i].sec;
		else if(vec[i].sec!=pos1&&vec[i].sec!=pos2){ans=max(ans,vec[i].fir);break;}
	}
	return writeln(ans),0;
}