bzoj2599 [IOI2011]Race

题目描述:

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

题解:

用桶存一下,然后每次换边的时候更新答案+合并桶。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200050
#define K 1000050
const int inf = 0x3f3f3f3f;
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,k,hed[N],cnt;
struct EG
{
    int to,nxt,v;
}e[2*N];
void ae(int f,int t,int v)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    e[cnt].v = v;
    hed[f] = cnt;
}
int rt,sum,v[N],siz[N];
int mrk[N];
void get_rt(int u,int fa)
{
    v[u]=0,siz[u]=1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(mrk[to]||to==fa)continue;
        get_rt(to,u);
        siz[u]+=siz[to];
        if(siz[to]>v[u])v[u]=siz[to];
    }
    v[u] = max(v[u],sum-siz[u]);
    if(v[u]<v[rt])rt=u;
}
struct Pair{int x,d;}p[N];
int tot;
int g[K],ans=inf,max_dis;
void dfs(int u,int fa,int dep,int dis)
{
    if(dis>k)return ;
    if(dis==k)
    {
        ans = min(ans,dep);
        return ;
    }
    p[++tot].x = dep,p[tot].d = dis;
    max_dis=max(max_dis,dis);
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==fa||mrk[to])continue;
        dfs(to,u,dep+1,dis+e[j].v);
    }
}
void work(int u)
{
    mrk[u] = 1;int mx = 0;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(mrk[to])continue;
        max_dis=0;tot=0;
        dfs(to,u,1,e[j].v);
        mx = max(mx,max_dis);
        for(int i=1;i<=tot;i++)
            if(g[k-p[i].d]!=inf)
                ans = min(ans,g[k-p[i].d]+p[i].x);
        for(int i=1;i<=tot;i++)
            if(g[p[i].d]>p[i].x)g[p[i].d]=p[i].x;
    }
    for(int i=1;i<=mx;i++)g[i]=inf;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(mrk[to])continue;
        rt=0,sum=siz[to];
        get_rt(to,0);
        work(rt);
    }
}
int main()
{
    n = rd(),k = rd();
    for(int ff,tt,vv,i=1;i<n;i++)
    {
        ff = rd()+1,tt = rd()+1,vv = rd();
        ae(ff,tt,vv),ae(tt,ff,vv);
    }
    memset(g,0x3f,sizeof(g));
    v[0]=inf;
    rt=0,sum=n;
    get_rt(1,0);
    work(rt);
    printf("%d\n",ans==inf?-1:ans);
    return 0;
}

 

posted @ 2018-12-28 13:39  LiGuanlin  阅读(113)  评论(0编辑  收藏  举报