[LOJ2330][树形DP]清华集训2017:榕树之心

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/89036151

LOJ2330

分析:假设现在心在位置 x x ,则心可以通过 x x 的不同子树的生长抵消移动,仍然停留在 x x 位置
当然也有无法停留在 x x 位置的情况:
第一种是 s i z [ x ] 1 siz[x]-1 为奇数,显然多出一次生长
第二种是 s i z siz 最大的子树的 s i z siz 过于大(大于1/2),所以一定会把心拉到里面去
那么我们就可以树形DP判断根节点是否可行了,设 w [ i ] w[i] 表示以 i i 为根的子树可以把外面的心往这边拉多少距离,很好处理
然后考虑从根节点扩展答案,设当前扩展到 y y ,考虑能不能把心从根弄到 y y
y y r t rt 的路径长度dep[y],当 s i z [ r t ] d e p [ y ] siz[rt]-dep[y] 为奇数时,不行,这表示除了这条路径的其他点无法抵消完全
那么如果为偶数,就把 r t > y rt->y 的路径看成一个点就完了

Code:

#include<bits/stdc++.h>
#define mod 998244353
#define N 300005
#define rt 1
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int W,t,n,cnt=0,siz[N],first[N],mx1[N],mx2[N],dep[N],f[N],w[N],ans[N];
struct edge{int v,next;}e[N<<1];
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline void dfs1(int p,int fa){
    siz[p]=1,mx1[p]=mx2[p]=0;
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa)continue;
        dep[v]=dep[p]+1,dfs1(v,p),siz[p]+=siz[v];
        if(siz[mx1[p]]<siz[v])mx2[p]=mx1[p],mx1[p]=v;
        else if(siz[mx2[p]]<siz[v])mx2[p]=v;
    }
    if(siz[p]-1>=siz[mx1[p]]+w[mx1[p]])w[p]=(siz[p]-1)%2;
    else w[p]=w[mx1[p]]-(siz[p]-1-siz[mx1[p]]);
    ++w[p];
}
inline void dfs2(int p,int fa){
    ans[p]=0;
    if((siz[rt]-dep[p])%2==0){
        int v=f[p];
        if(siz[v]<siz[mx1[p]])v=mx1[p];
        if(siz[rt]-dep[p]-siz[v]-w[v]>=0)ans[p]=1;
    }
    for(int i=first[p];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa)continue;
        f[v]=f[p];
        if(v!=mx1[p]&&siz[mx1[p]]>siz[f[v]])f[v]=mx1[p];
        else if(siz[mx2[p]]>siz[f[v]])f[v]=mx2[p];
        dfs2(v,p);
    }
}
int u,v;
int main(){
    W=read(),t=read();
    while(t--){
        n=read(),cnt=0,memset(first,0,sizeof(first));
        for(int i=1;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
        dep[1]=1,dfs1(1,1),f[1]=0,dfs2(1,1);
        if(W==3)putchar(ans[1]^48);
        else for(int i=1;i<=n;++i)putchar(ans[i]^48);
        puts(""); 
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/89036151