BZOJ2599: [IOI2011]Race

Description

给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000

 

Input

第一行 两个整数 n, k
第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始)

Output

一个整数 表示最小边数量 如果不存在这样的路径 输出-1

 

Code:

// luogu-judger-enable-o2
#include<bits/stdc++.h> 
using namespace std;
const int maxn=3000000; 
void setIO(string s)
{
    string in=s+".in",out=s+".out"; 
    freopen(in.c_str(),"r",stdin); 
    // freopen(out.c_str(),"w",stdout); 
}
int root,sn,edges,n,K,tl,tr,ans=1000000000; 
int f[maxn],siz[maxn],vis[maxn],hd[maxn],to[maxn],nex[maxn],val[maxn],dis1[maxn],dis2[maxn],mine[maxn];   
void addedge(int u,int v,int c)
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; 
}
void getroot(int u,int ff)
{
    siz[u]=1,f[u]=0; 
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==ff||vis[v]) continue; 
        getroot(v,u); 
        siz[u]+=siz[v];  
        f[u]=max(f[u],siz[v]);            
    } 
    f[u]=max(f[u],sn-siz[u]); 
    if(f[u]<f[root])root=u; 
}
void getdis(int u,int ff,int d1,int d2)
{
    if(d1>K) return; 
    dis1[++tl]=d1,dis2[tl]=d2; 
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==ff||vis[v]) continue; 
        getdis(v,u,d1+val[i],d2+1);  
    }
}
void dfs(int u)
{
    mine[0]=0,tl=0; 
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(vis[v]) continue; 
        int pdl=tl; 
        getdis(v,u,val[i],1);          
        for(int j=pdl+1;j<=tl;++j) ans=min(ans,mine[K-dis1[j]]+dis2[j]); 
        for(int j=pdl+1;j<=tl;++j) mine[dis1[j]]=min(mine[dis1[j]], dis2[j]); 
    }
    for(int i=1;i<=tl;++i) mine[dis1[i]]=1000000000; 
}
void Get(int u)
{
    vis[u]=1; 
    dfs(u); 
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(vis[v]) continue; 
        root=0,sn=siz[v]; 
        getroot(v,u); 
        Get(root); 
    }
}
int main()
{
    // setIO("input");
    scanf("%d%d",&n,&K);
    for(int i=1,u,v,c;i<n;++i)
    {
        scanf("%d%d%d",&u,&v,&c),++u,++v; 
        addedge(u,v,c),addedge(v,u,c); 
    }
    for(int i=0;i<maxn;++i) mine[i]=1000000000; 
    vis[0]=1,sn=n,root=0,f[0]=100000000,getroot(1,0),Get(root); 
    printf("%d\n",ans>=n?-1:ans); 
    return 0; 
}

  

posted @ 2019-05-28 19:42  EM-LGH  阅读(163)  评论(0编辑  收藏  举报