BZOJ 2599 Race(树分治)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2599

题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.

题意:每次找到当前树的重心作为树根,查找通过当前树根的路径。

 


 
struct node
{
    int v,w;
     
    node(){}
    node(int _v,int _w)
    {
        v=_v;
        w=_w;
    }
};
 
vector<node> g[N];
int n,m;
int dis[N*5],cnt[N*5],h[N*5];
int visit[N];
int ans;
int f[N],s[N];
 
vector<int> V;
 
void dfs(int u,int pre)
{
    V.pb(u); s[u]=1;
    int i,v,Max=0;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i].v;
        if(visit[v]||v==pre) continue;
        dfs(v,u);
        s[u]+=s[v];
        upMax(Max,s[v]);
    }
    f[u]=Max;
}
 
int getRoot(int u)
{
    V.clear(); 
    dfs(u,-1);
    int Min=n,ans=u,i,temp;
    FOR0(i,SZ(V))
    {
        u=V[i];
        temp=max(f[u],(int)SZ(V)-f[u]);
        if(temp<Min) Min=temp,ans=u;
    }
    return ans;
}
 
int d[N],K,a[N*5];
 
void dfs1(int u,int pre)
{
    if(dis[u]>m) return;
    if(h[m-dis[u]]==K) upMin(ans,a[m-dis[u]]+cnt[u]);
    int i,v,w;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i].v;
        w=g[u][i].w;
        if(v==pre||visit[v]) continue;
        dis[v]=dis[u]+w;
        cnt[v]=cnt[u]+1;
        dfs1(v,u);
    }
}
 
 
void dfs2(int u,int pre)
{
    if(dis[u]>m) return;
    if(h[dis[u]]!=K) a[dis[u]]=cnt[u],h[dis[u]]=K;
    else upMin(a[dis[u]],cnt[u]);
    int i,v;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i].v;
        if(v==pre||visit[v]) continue;
        dfs2(v,u);
    }
}
 
void DFS(int u)
{
    u=getRoot(u); h[0]=++K;
    int i,v,w;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i].v;
        w=g[u][i].w;
        if(visit[v]) continue;
        dis[v]=w;
        cnt[v]=1;
        dfs1(v,u);
        dfs2(v,u);
    }
    visit[u]=1;
    FOR0(i,SZ(g[u]))
    {
        v=g[u][i].v;
        if(visit[v]) continue;
        DFS(v);
    }
}
 
int main()
{
    RD(n,m);
    int i,x,y,w;
    FOR1(i,n-1)
    {
        RD(x,y,w);
        g[x].pb(node(y,w));
        g[y].pb(node(x,w));
    }
    ans=n; DFS(0);
    if(ans==n) ans=-1;
    PR(ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值