2019牛客多校第四场 A meeting

考场上写了一大坨树形DP,写的时候就感觉我这不是跟求树的最长链写的一毛一样

然后考后看题解,果然是k个ren所连成的子树的最长链的一半

可以利用反证法证明,如果在长度为d的最长链的中间放一个中心,如果有另外一个点到这个点的长度>(d+1)/2,那么这个点到对面的那个点的长度大于d,所以不存在这样一个点。

#include<bits/stdc++.h>
#define maxl 100010
using namespace std;

int n,cnt,k,ans;
int a[maxl],ehead[maxl],dis[maxl];
struct ed
{
	int to,nxt;
}e[maxl*2];
bool in[maxl],vis[maxl];

inline void add(int u,int v)
{
	e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}

inline void prework()
{
	for(int i=1;i<=n;i++)
		ehead[i]=0,in[i]=false;
	int u,v;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	for(int i=1;i<=k;i++)
	{
		scanf("%d",&a[i]);
		in[a[i]]=true;
	}
}

inline void dfs(int u)
{
	vis[u]=true;
	int v;
	for(int i=ehead[u];i;i=e[i].nxt)
	{
		v=e[i].to;
		if(!vis[v])
		{
			dis[v]=dis[u]+1;
			dfs(v);
		}
	}
}

inline void mainwork()
{
	if(k<=1)
	{
		ans=0;
		return;
	}
	for(int i=1;i<=n;i++)
		vis[i]=false,dis[i]=0;
	dfs(a[1]);
	int u=a[1];
	for(int i=1;i<=k;i++)
	if(dis[a[i]]>dis[u])
		u=a[i];
	for(int i=1;i<=n;i++)
		vis[i]=false,dis[i]=0;
	dfs(u);
	int v=u;
	for(int i=1;i<=k;i++)
	if(dis[a[i]]>dis[v])
		v=a[i];
	ans=(dis[v]+1)/2;
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	while(~scanf("%d%d",&n,&k))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

 

树形DP版本,又臭又长:

 

 

#include<bits/stdc++.h>
#define maxl 100010
 
using namespace std;
const int inf=2e9;
 
int n,k,cnt,ans;
int ehead[maxl];
int f[maxl],mxfa[maxl],mxs[maxl],secmxs[maxl];
bool mxflag[maxl],secmxflag[maxl],faflag[maxl];
struct ed
{
    int to,nxt,mi;
}e[maxl<<1];
bool in[maxl];
 
inline void add(int u,int v)
{
    e[++cnt].to=v;e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
 
inline void prework()
{
    for(int i=1;i<=n;i++)
        ehead[i]=0,f[i]=0,in[i]=false;
    int u,v;
    cnt=0;
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&u);
        in[u]=true;
    }
}
 
inline void gets(int u,int fa)
{
    int v,tmp;
    if(in[u])
        mxflag[u]=true;
    for(int i=ehead[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if(v==fa) continue;
        gets(v,u);
        if(in[v])
        {
            in[u]=true;
            if(mxflag[v])
            {
                tmp=mxs[v]+1;
                if(tmp>mxs[u])
                {
                    secmxs[u]=mxs[u],mxs[u]=tmp;
                    secmxflag[u]=mxflag[u];
                    mxflag[u]=true;
                }
                else if(tmp>secmxs[u])
                    secmxs[u]=tmp,secmxflag[u]=true;
            }
        }
    }  
}
 
inline void getf(int u,int fa)
{
    int v,tmp;
    if(u==1) f[1]=mxs[1];
    else
    {
        if(mxs[u]+1==mxs[fa])
        {
            if(secmxflag[fa])
            {
                mxfa[u]=max(mxfa[u],secmxs[fa]+1);
                faflag[u]=true;
            }
        }
        else
        {
            if(mxflag[fa])
            {
                mxfa[u]=max(mxfa[u],mxs[fa]+1);
                faflag[u]=true;
            }
        }
        if(faflag[fa])
        {  
            mxfa[u]=max(mxfa[u],mxfa[fa]+1);
            faflag[u]=true;
        }
    }
    for(int i=ehead[u];i;i=e[i].nxt)
    {
        v=e[i].to;
        if(v==fa) continue;
        getf(v,u);
    }
    if(faflag[u])
        f[u]=mxfa[u];
    if(mxs[u])
        f[u]=max(f[u],mxs[u]);
}
 
inline void mainwork()
{
    for(int i=1;i<=n;i++){
        f[i]=0,mxs[i]=0,secmxs[i]=0,mxfa[i]=0;
        mxflag[i]=secmxflag[i]=faflag[i]=false;
    }
    gets(1,0);
    mxfa[1]=0;
    getf(1,0);
    ans=inf;
    for(int i=1;i<=n;i++)
        ans=min(ans,f[i]);
}
 
inline void print()
{
    printf("%lld\n",ans);
}
 
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        prework();
        mainwork();
        print();
    }
    return 0;
}

 

上一篇:Find the median 2019牛客多校第七场 E


下一篇:2019牛客多校第二场