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

传送门:loj2330


题解

先考虑根的情况( Subtask 3 S u b t a s k   3 )。
根的每个儿子及其构成的子树之间可以互相抵消。
rem[i] r e m [ i ] 表示以 i i 为根的子树最少的不能互相抵消的点数。
那么考虑根的最大儿子 mx[1] m x [ 1 ]
sz[1]1sz[mx[1]]rem[mx[1]] s z [ 1 ] − 1 − s z [ m x [ 1 ] ] ≤ r e m [ m x [ 1 ] ] ,大儿子可以被抵消掉,这时只需考虑 sz[1]1 s z [ 1 ] − 1 是否为偶数即可。
否则 rem[1]=rem[mx[1]]sz[1]+sz[mx[1]]+2 r e m [ 1 ] = r e m [ m x [ 1 ] ] − s z [ 1 ] + s z [ m x [ 1 ] ] + 2
其他 Subtask S u b t a s k ,把当前节点到根节点的这条链看做根,顺便记一下每个点的第二大儿子 mxx[i]res[i] m x x [ i ] , r e s [ i ] 存一下这条链为根的最大儿子。 dfs d f s 一遍即可。


代码

#include
using namespace std;
const int N=1e5+10;

int W,T,n,d[N],sz[N],ans[N];
int rem[N],mx[N],mxx[N],f[N],res[N];
int head[N],to[N<<1],nxt[N<<1],tot;

inline int rd()
{
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

inline void dfs(int x)
{
    int i,j;
    d[x]=d[f[x]]+1;sz[x]=1;mx[x]=mxx[x]=0;
    for(i=head[x];i;i=nxt[i]){
        j=to[i];if(j==f[x]) continue;
        f[j]=x;dfs(j);sz[x]+=sz[j];
        if(sz[mx[x]]else if(sz[mxx[x]]if(sz[x]-1-sz[mx[x]]>=rem[mx[x]]) rem[x]=((sz[x]-1)&1)+1;
    else rem[x]=rem[mx[x]]-sz[x]+2+sz[mx[x]];
}

inline void df(int x)
{
    int i,j;ans[x]=0;
    if(!((sz[1]-d[x])&1)){
        j=res[x];if(sz[mx[x]]>sz[res[x]]) j=mx[x];
        if((sz[1]-d[x]-sz[j])>=rem[j]) ans[x]=1;
    }
    for(i=head[x];i;i=nxt[i]){
        j=to[i];if(j==f[x]) continue;
        res[j]=res[x];
        if((j!=mx[x])&&(sz[mx[x]]>sz[res[j]])) res[j]=mx[x];
        else if(sz[mxx[x]]>sz[res[j]]) res[j]=mxx[x];
        df(j);
    }
}

int main(){
    int i,j,ix,iy;
    W=rd(),T=rd();
    while(T--){
        n=rd();
        for(tot=0,i=1;i<=n;++i) head[i]=0;
        for(i=1;i1);
        if(W==3){
            if((!((sz[1]-1)&1)) && (sz[1]-1-sz[mx[1]])>=rem[mx[1]]) puts("1");
            else puts("0");
        }else{
            res[1]=0;df(1);
            for(i=1;i<=n;++i) printf("%c",'0'+ans[i]);
            puts("");
        }
    }
}

你可能感兴趣的:(妙,树形DP)