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");
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12116670.html