[IOI2011]Race

题目描述

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

输入输出格式

输入格式:

 

第一行:两个整数 n,k。

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

 

输出格式:

 

一个整数,表示最小边数量。

如果不存在这样的路径,输出 -1

 

输入输出样例

输入样例#1: 
4 3
0 1 1
1 2 2
1 3 4
输出样例#1: 
2

说明

N<=2*10^5,K<=1*10^6。

IOI签到题,裸点分

#include<bits/stdc++.h>
#define ll long long
#define maxn 200005
#define pb push_back
using namespace std;
const int inf=1<<29; 
int tag[maxn*5],n,k;
int num,d[maxn],mn,dep[maxn];
bool done[maxn];
int siz[maxn],ans=inf,hd[maxn];
int root,sz,to[maxn*2],tot;
int ne[maxn*2],val[maxn*2];

inline void add(int uu,int vv,int ww){
    to[++tot]=vv,ne[tot]=hd[uu],hd[uu]=tot,val[tot]=ww;
    to[++tot]=uu,ne[tot]=hd[vv],hd[vv]=tot,val[tot]=ww;
}

void find_root(int x,int fa){
    siz[x]=1;
    int bal=0;
    for(int i=hd[x];i;i=ne[i]){
        if(to[i]==fa||done[to[i]]) continue;
        find_root(to[i],x);
        siz[x]+=siz[to[i]];
        bal=max(bal,siz[to[i]]);
    }
    
    bal=max(bal,sz-siz[x]);
    if(bal<mn) mn=bal,root=x;
}

int find_siz(int x,int fa){
    int an=1;
    for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa&&!done[to[i]]){
        an+=find_siz(to[i],x);
    }
    return an;
}

void get_dep(int x,int fa,int dis,int dp){
    if(dis<=k){
        ans=min(ans,dp+tag[k-dis]);
        d[++num]=dis,dep[num]=dp;
    }
    
    for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa&&!done[to[i]]){
        get_dep(to[i],x,dis+val[i],dp+1);
    }
}

inline void calc(int x,int dis){
    int pre=num;
    get_dep(x,x,dis,1);
    
    for(int i=pre+1;i<=num;i++) tag[d[i]]=min(tag[d[i]],dep[i]);
}

inline void work(int x,int trsiz){
    sz=trsiz,mn=inf;
    find_root(x,x);
    done[root]=1;
    
    tag[0]=0;
    for(int i=hd[root];i;i=ne[i]) if(!done[to[i]]){
        calc(to[i],val[i]);
    }
    
    for(int i=1;i<=num;i++) tag[d[i]]=inf;
    num=0,tag[0]=inf;
    
    for(int i=hd[root];i;i=ne[i]) if(!done[to[i]]){
        work(to[i],find_siz(to[i],to[i]));
    }
}

int main(){
    memset(tag,0x3f,sizeof(tag));
    
    int uu,vv,ww;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++){
        scanf("%d%d%d",&uu,&vv,&ww);
        add(uu,vv,ww);
    }
    
    work(1,n);
    
    if(ans==inf) puts("-1");
    else printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-01-26 20:58  蒟蒻JHY  阅读(267)  评论(0编辑  收藏  举报