十一联考 1T2 树链剖分

Posted white-star

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十一联考 1T2 树链剖分相关的知识,希望对你有一定的参考价值。

算法思路就不说了,其实比较简单

这里讲一下坑点:

1.虽然我们可以将边权压到点上,但是当根不同时,差分数组显然不同。所以我们不能真的将边权看做点权,换根时还是要将其当做边权来考虑。
1.更新时,我们设dp[u]表示u节点为根时的最大价值,由于经过点u后,点v的儿子将变成点u,所以此时我们要更新点v的儿子中的最大值以及次大值。注意!不止要更新最大值,次大值也要正确维护

我的代码没有加优化,因为保证正确就不错了

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

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define head(x) for(int i=head[x];i+1;i=e[i].nxt)
#define int long long

const int inf=0x3f3f3f3f3f3f3f3f,N=1e5+10,t=17;

int n,m,head[N],cnt,son[N],c[N],dep[N],f[N][20],mx[N],se[N],ans=0,dp[N];

struct edge{
    int nxt,v;
}e[N*2];

void add(int u,int v){
    e[cnt]=(edge){head[u],v};
    head[u]=cnt++;
}

inline void read(int &x){
    x=0;char f=1,c=getchar();
    while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

void dfs(int u,int fa){
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    head(u){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
    }
}

int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    com(i,t,0){
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    }
    if(x==y) return x;
    com(i,t,0){
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}

void Dfs(int u,int fa){
    head(u){
        int v=e[i].v;
        if(v==fa) continue;
        Dfs(v,u);
        c[u]+=c[v];
    }
}

void DFS(int u,int fa){
    head(u){
        int v=e[i].v;
        if(v==fa) continue;
        DFS(v,u);
        if(c[v]>=mx[u]){
            se[u]=mx[u];
            mx[u]=c[v];
        }
        else if(c[v]>se[u]) se[u]=c[v];
    }
    dp[1]+=mx[u];
}

void DFs(int u,int fa){
    head(u){
        int v=e[i].v;
        if(v==fa) continue;
        dp[v]=dp[u];
        if(mx[u]==c[v]) dp[v]=dp[v]-mx[u]+se[u];
        if(c[v]>=mx[v]){
            dp[v]=dp[v]+c[v]-mx[v];
            se[v]=mx[v];
            mx[v]=c[v];
        }
        else if(c[v]>se[v]) se[v]=c[v];
        DFs(v,u);
    }
}

signed main(){
    mem(head,-1);
    read(n),read(m);
    int u,v,Lca;
    go(i,2,n){
        read(u),read(v);
        add(u,v),add(v,u);
    }
    dfs(1,0);
    go(j,1,t)
        go(i,1,n)
            f[i][j]=f[f[i][j-1]][j-1];
    while(m--){
        read(u),read(v);
        Lca=lca(u,v);
        ++c[u],++c[v];
        c[Lca]-=2;
        ans+=dep[u]+dep[v]-2*dep[Lca];
    }
    Dfs(1,0);
    DFS(1,0);   
    DFs(1,0);
    int tot=ans;
    go(i,1,n)
        ans=min(ans,tot-dp[i]);
    printf("%lld",ans);
    return 0;
}

以上是关于十一联考 1T2 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章

树的统计Count---树链剖分

BZOJ 2243--染色(树链剖分)

树链剖分详解

树链剖分小结

树链剖分详解

树链剖分