Focus CSP2019 tree explanations

Of course this question can then use various data structures maintained by the size of the relationship between violence and vigorously discuss each of them the size of the sub-tree. But I prefer to use a more nature approach.

I think first of all talk about practice in the examination room (I did not write). Root is considered for calculating the center of gravity of each of the two sub-trees obtained after deleting an edge in the process of changing the root, since the center of gravity of some properties, if we put all the sons of v to seek the center of gravity of the root of the subtree out, then when we asked to point v is the root of the subtree center of gravity, you can guarantee that the focus must be in the focus of heavy son subtree of v to the chain v, then we can multiply by the chain to achieve multi-subtrees of the combined center of gravity. Each tree maintenance point size, and the center of gravity when changing the subtree root, multiplication can be the center of gravity when changing novelty subtree root.

Code:

#include<bits/stdc++.h>
using namespace std;
#define N 300007
#define M 600007
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
int hd[N],pre[M],to[M],num,wa[N],wb[N],sz[N],ts,dep[N];
int anc[N][23],ms[N],n;
ll ans;

void clear()
{
    mem(hd),mem(wa),mem(wb),mem(sz);
    mem(dep),mem(ms);
    num=0;ans=0;
}
    
int calc(int v)
{
    return max(ms[v],ts-sz[v]);
}
void solve(int x,int d,int &a,int &b)
{
    if(dep[x]<d)return;
    for(int i=20;i>=0;i--)
    {
        int mid=anc[x][i],y=anc[mid][0];
        if(dep[y]>=d&&calc(mid)>=calc(y))
            x=mid;
    }
    int y=anc[x][0];
    int dx=calc(x),dy=calc(y);
    if(dep[x]==d||dx<dy)
    {
        if(dx<=ts/2)a=x;
    }
    else
    {
        if(dy<=ts/2)
        {
            a=y;
            if(dx==dy)b=x;
        }
    }
}
/*void solve(int x,int d,int &a,int &b)
{
    while(dep[x]>=d)
    {
        if(calc(x)<=ts/2)
        {
            if(a)b=x;
            else a=x;
        }
        x=anc[x][0];
    }
}*/
int glca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;i>=0;i--)
        if(dep[x]-dep[y]>=(1<<i))
            x=anc[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--)
        if(anc[x][i]!=anc[y][i])
            x=anc[x][i],y=anc[y][i];
    return anc[x][0];
}
int dmax(int x,int y)
{
    return dep[x]>dep[y]?x:y;
}
int dmin(int x,int y)
{
    return dep[x]<dep[y]?x:y;
}   
void dfs(int v,int f)
{
    dep[v]=dep[f]+1;
    anc[v][0]=f;
    for(int i=1;i<=20;i++)
        anc[v][i]=anc[anc[v][i-1]][i-1];
    sz[v]=1;
    int son=v;
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(u==f)continue;
        dfs(u,v);
        sz[v]+=sz[u];
        if(sz[u]>ms[v])ms[v]=sz[u],son=u;
    }
    ts=sz[v];
    int x=( son==v ? v : dmax(wa[son],wb[son]) );
    solve(x,dep[v],wa[v],wb[v]);
}
void dp(int v,int f)
{
    int s1,d1,s2,d2;
    s1=d1=s2=d2=0;
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(sz[u]>s1)s2=s1,d2=d1,s1=sz[u],d1=u;
        else if(sz[u]>s2)s2=sz[u],d2=u;
    }
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(u==f)continue;
        int x=d1;
        if(u==d1)x=d2;
        
        int _ms=ms[v],_wa=wa[v],_wb=wb[v];
        
        sz[v]-=sz[u],sz[u]+=sz[v];
        ms[v]=sz[x];
        wa[v]=wb[v]=0;
        ts=sz[v];
        
        int p=dmax(wa[x],wb[x]);
        //if(p==0)printf("WA\n");
        if(x==f)
        {
            int q=dmin(wa[x],wb[x]);
            int lca=glca(p,v);
            if(q!=0&&q==anc[lca][0])p=q,lca=p;
            solve(p,dep[lca],wa[v],wb[v]);
            solve(v,dep[lca]+1,wb[v],wa[v]);
        }
        else
        {
            solve(p,dep[v],wa[v],wb[v]);
        }   
        
        /*if(!wa[v]&&!wb[v])
        {
            printf("%d\n",v);
            printf("%d\n",x);
        }*/
        ans+=wa[v]+wb[v]+wa[u]+wb[u];
        dp(u,v);
        
        wa[v]=_wa,wb[v]=_wb;
        ms[v]=_ms;
        sz[u]-=sz[v],sz[v]+=sz[u];
    }
    
}
void adde(int x,int y)
{
    num++;pre[num]=hd[x];hd[x]=num;to[num]=y;
}
void dewa()
{
    for(int i=1;i<=n;i++)
        printf("%d: %d %d\n",i,wa[i],wb[i]);
}

int main()
{
    //freopen("data.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        clear();
        int x,y;
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            adde(x,y),adde(y,x);
        }
        dfs(1,0);
        //dewa();
        dp(1,0);
        printf("%lld\n",ans);
    }
    return 0;
}

There is also a solution to a problem approach, also using the properties of gravity, but more clever than I am, but also easier to achieve.
Is to consider how to find its center of gravity to a certain point v is the root can be found from the point of v, the center of gravity of the path must continue to walk along the heavy son, and every point of heavy son is unique, so we doubled optimization of process re-son walking along, let f [i] [j] to start from the point i, go \ (2 ^ j \) bolted for the position, as long as we find the last meet \ (2 * size [v] \ GEQ sum \) is the point to which the sum is the size of the cutting edge of the current block communication. Also like the former approach as to change the root, note that f [i] [j] is maintained by changing the root.

Problem solution approach:

#include<bits/stdc++.h>
using namespace std;
#define N 300007
#define M 600007
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
int hd[N],pre[M],to[M],num,son[N],fa[N],sz[N];
int ch[N][23],n;
ll ans;
void clear()
{
    mem(hd),mem(son);
    ans=0,num=0;
}
void adde(int x,int y)
{
    num++;pre[num]=hd[x];hd[x]=num;to[num]=y;
}
void mak_st(int v)
{
    for(int i=1;i<=20;i++)
        ch[v][i]=ch[ch[v][i-1]][i-1];
}
void dfs(int v,int f)
{
    fa[v]=f,sz[v]=1;
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(u==f)continue;
        dfs(u,v);
        sz[v]+=sz[u];
        if(sz[u]>sz[son[v]])son[v]=u;
    }
    ch[v][0]=son[v];
    mak_st(v);
}
void solve(int x,int ts)
{
    for(int i=20;i>=0;i--)
    {
        int y=ch[x][i];
        if(y&&2*sz[y]>=ts)x=y;
    }
    ans+=x;
    if(2*sz[x]==ts)ans+=fa[x];
}
void dp(int v,int f)
{
    int s1,s2;
    s1=s2=0;
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(sz[u]>sz[s1])s2=s1,s1=u;
        else if(sz[u]>sz[s2])s2=u;
    }
    for(int i=hd[v];i;i=pre[i])
    {
        int u=to[i];
        if(u==f)continue;
        int x=s1;
        if(u==s1)x=s2;
        
        sz[v]-=sz[u];
        ch[v][0]=x;
        mak_st(v);
        
        solve(v,sz[v]),solve(u,sz[u]);
        
        sz[u]+=sz[v],fa[v]=u;
        
        dp(u,v);
        
        sz[u]-=sz[v],sz[v]+=sz[u];
    }
    ch[v][0]=son[v];
    mak_st(v);
    fa[v]=f;
}
int main()
{
    //freopen("data.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        clear();
        scanf("%d",&n); 
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            adde(x,y),adde(y,x);
        }
        dfs(1,0),dp(1,0);
        printf("%lld\n",ans);
    }
    return 0;
}

Comparison of the two approaches and found that in fact is the nature of the use of heavy son, but my approach is severely son to root in the sub-tree walk, and problem solution approach is to re-son away from the roots. Why do I approach problem solution is shorter than a lot of it?
Because I multiplier array is doubled from the bottom up, the root of the root of change when change will result in doubling the array change all descendants of nodes below, then change the root can not be maintained in the process, so I have been on a number of multiplier array 1:00 as the root, the more severe the son of the current point is to discuss or come from the direction of his son from his father in a direction as root. The solution to a problem from the doubling down, will not lead to a change in the following points when changing the root, and the reason can be from top to bottom multiplication problem solution is the use of the properties of each point will go to the only son of weight, then each point of departure walked several steps away is the only point, you can double up.

I was in Los solution to a problem in the valley, we saw a vigorous discussion of the problem solution subtree size, which counts some tips still a little meaning, for example, after the calculation of each edge cut sub-label of the tree and into the center of gravity for each a calculation point it will become the center of child tree after how many sides are cut off, we can look at. Mr_Wu's blog

Guess you like

Origin www.cnblogs.com/lishuyu2003/p/11896697.html