loj#2330. 「清华集训 2017」榕树之心【树形dp】

传送门

解题思路:

先考虑根是否可行,即步数是否能抵消完。
考虑 w [ x ] 表示 x 的子树内最少的消剩下的点数。

观察发现,最难消的肯定是 s i z e 最大的儿子,设为 y ,而且如果 y 能被消完,即 o t h e r s = s i z e [ x ] 1 s i z e [ y ] >= w [ y ] ,那么 w [ x ] 最多在 s i z e [ x ] 为奇数时剩一个子节点没被消,否则肯定能消完(除了自己)。
如果 y 不能被消完,那么 w [ x ] = w [ y ] o t h e r s + 1

再考虑每个节点是否合法。
其实思路就比较简单了,将根到 x 的路径当做新根(根肯定能走到 x ,且不影响路径上的子树),用与上面类似的方法判断即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll getint()
{
    ll i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=100005;
int W,n;
int size[N],dep[N],w[N],mx1[N],mx2[N],dp[N],ans[N];
int tot,first[N],nxt[N<<1],to[N<<1];
void add(int x,int y)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void dfs1(int u,int fa)
{
    size[u]=1,dep[u]=dep[fa]+1,mx1[u]=mx2[u]=0;
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];if(v==fa)continue;
        dfs1(v,u),size[u]+=size[v];
        if(size[v]>size[mx1[u]])mx2[u]=mx1[u],mx1[u]=v;
        else if(size[v]>size[mx2[u]])mx2[u]=v;
    }
    if(size[u]-1-size[mx1[u]]>=w[mx1[u]])w[u]=(size[u]-1)%2;
    else w[u]=w[mx1[u]]-(size[u]-1-size[mx1[u]]);
    w[u]++;
}
void dfs2(int u,int fa)
{
    ans[u]=0;
    if((size[1]-dep[u])%2==0)
    {
        int v=dp[u];if(size[v]<size[mx1[u]])v=mx1[u];
        if(size[1]-dep[u]-size[v]>=w[v])ans[u]=1;
    }
    for(int e=first[u];e;e=nxt[e])
    {
        int v=to[e];if(v==fa)continue;
        dp[v]=dp[u];
        if(v!=mx1[u]&&size[mx1[u]]>size[dp[v]])dp[v]=mx1[u];
        else if(size[mx2[u]]>size[dp[v]])dp[v]=mx2[u];
        dfs2(v,u);
    }
}
void solve()
{
    tot=0;memset(first,0,sizeof(first));
    n=getint();
    for(int i=1;i<n;i++)
    {
        int x=getint(),y=getint();
        add(x,y),add(y,x);
    }
    dfs1(1,0);
    dp[1]=0,dfs2(1,0);
    if(W==3)putchar('0'+ans[1]);
    else for(int i=1;i<=n;i++)putchar('0'+ans[i]);
    putchar('\n');
}
int main()
{
    //freopen("lx.in","r",stdin);
    W=getint();for(int T=getint();T;T--)solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80455980
今日推荐