CF1266F

题意

给出一棵树,对于k=1~n求最大点集S满足dis(i,j)=k或k+1(i,j∈S & i≠j)

题解

首先答案满足ans[i]>=ans[i+2],因此可以维护后缀

分类讨论

①k=1

最大点集为最大度数+1

②k为奇数

考虑一个中心点u,那么点集S满足任意一个在S中的点到u的距离为(k-1)/2或(k+1)/2,且最多只能有一个为(k-1)/2

根据偶数的情况画一下,发现不能分成两个中心,然后又可以发现只能有一个特殊即可得到

把度数排序,讨论一下特殊情况即可

③k为偶数

分两种情况,第一种同k为奇数,只不过到u的距离只能为k/2

第二种为一条边(u,v),S中的点满足以u为根时到v距离为k/2,或以v为根时到u距离为k/2

这样暴力搞是O(n^2)的,但是可以发现不同深度的种类是\(\sqrt n\)的,所以把深度相同的合并再做即可

注意ans[i]至少为1

时间复杂度:\(O(n\sqrt n)\)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
//#define file
using namespace std;

int a[1000001][3];
int ls[500001];
int ans[500001];
int d[500001];
int fd[500001];
int b[500001];
int deg[500001];
int fa[500001];
vector<int> c[500001];
int n,i,j,k,l,len,tot;

void New(int x,int y)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
}

void dfs(int Fa,int t)
{
	int i;
	fa[t]=Fa;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		dfs(t,a[i][0]);
		d[t]=max(d[t],d[a[i][0]]+1);
	}
}

void Dfs(int Fa,int t,int D)
{
	int i,j,k,l,mx=0,Mx=-1,mx2=0;
	fd[t]=D;tot=0;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		a[i][2]=d[a[i][0]]+1;
		
		if (d[a[i][0]]+1>mx)
		mx2=mx,mx=d[a[i][0]]+1,Mx=a[i][0];
		else
		if (d[a[i][0]]+1>mx2)
		mx2=d[a[i][0]]+1;
		
		b[++tot]=d[a[i][0]]+1;
	}
	else
	a[i][2]=D;
	if (D) b[++tot]=D;
	
	sort(b+1,b+tot+1);
	j=0;
	fo(i,1,tot)
	{
		if (b[i]==b[i-1])
		++j;
		else
		j=1;
		
		if (i==tot || b[i]!=b[i+1])
		c[t].push_back(b[i]),c[t].push_back(j);
	}
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	{
		if (a[i][0]!=Mx)
		Dfs(t,a[i][0],max(D,mx)+1);
		else
		Dfs(t,a[i][0],max(D,mx2)+1);
	}
}

void work0() //k=1
{
	int t,i;
	
	fo(t,1,n)
	{
		for (i=ls[t]; i; i=a[i][1])
		++deg[t];
		
		ans[1]=max(ans[1],deg[t]+1);
	}
}

void work1() //one
{
	int N,t,i,j,k,l,sum,s1,s2;
	
	fo(t,1,n)
	{
		N=c[t].size()/2;
		sum=deg[t];
		
		fo(i,1,N)
		{
			s1=c[t][i*2-2],s2=c[t][i*2-1];
			
			ans[s1*2]=max(ans[s1*2],sum); //even
			
			ans[s1*2-1]=max(ans[s1*2-1],sum); //odd
			if (sum>s2)
			ans[s1*2+1]=max(ans[s1*2+1],sum-s2+1);
			
			sum-=s2;
		}
	}
}

void work2() //two
{
	int N,x,y,d1,d2,i,j,k,l,n1,n2,sum1,sum2;
	
	fo(x,1,n)
	{
		for (i=ls[x]; i; i=a[i][1])
		if (a[i][0]!=fa[x])
		{
			y=a[i][0];
			d1=a[i][2];
			d2=fd[y];
			
			n1=c[x].size();sum1=deg[x]-1;
			n2=c[y].size();sum2=deg[y]-1;
			
			j=k=0;
			while (j<n1 || k<n2)
			{
				if (j<n1 && c[x][j]==d1 && c[x][j+1]==1) j+=2;
				if (k<n2 && c[y][k]==d2 && c[y][k+1]==1) k+=2;
				
				if (j<n1 && (k==n2 || c[x][j]<c[y][k]))
				ans[c[x][j]*2]=max(ans[c[x][j]*2],sum1+sum2),sum1-=c[x][j+1],j+=2;
				else
				if (k<n2)
				ans[c[y][k]*2]=max(ans[c[y][k]*2],sum1+sum2),sum2-=c[y][k+1],k+=2;
			}
		}
	}
}

int main()
{
	#ifdef file
	freopen("CF1266F.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	fo(i,2,n)
	{
		scanf("%d%d",&j,&k);
		
		New(j,k);
		New(k,j);
	}
	
	ans[n-1]=ans[n]=1;
	
	dfs(0,1);
	Dfs(0,1,0);
	
	work0();
	work1();
	work2();
	
	fd(i,n,3)
	ans[i-2]=max(ans[i-2],ans[i]);
	
	fo(i,1,n)
	printf("%d ",ans[i]);
	printf("\n");
}
posted @ 2019-12-29 21:44  gmh77  阅读(279)  评论(0编辑  收藏  举报