[IOI2011]Race

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

淀粉质的题,直接套淀粉质的板子,再维护一个桶,表示到达dis的最小需要的路径。
但是有个奇怪的东西,就是如果我最后还原的时候用栈储存所有的dis就会WA4个点,但是如果我把dfs重做一遍就没事了。。。WA了1页。。。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,k,head[200005],ecnt,rt,f[200005],siz[200005],size;
struct Edge{int to,nxt,val;}e[400005];
bool vis[200005];
void add(int bg,int ed,int val) {e[++ecnt]=(Edge){ed,head[bg],val};head[bg]=ecnt;}
void barycenter(int x,int fa) {
    f[x]=0,siz[x]=1;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(v==fa||vis[v]) continue;
        barycenter(v,x),f[x]=max(f[x],siz[v]),siz[x]+=siz[v];
    }
    f[x]=max(f[x],size-siz[x]);
    if(f[x]<f[rt]) rt=x;
}
int dis[1000005],stk[1000005],top,ans;
bool used[1000005];
void dfs(int x,int fa,int val,int along) {
    dis[val]=min(dis[val],along);
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(vis[v]||v==fa) continue;
        if(val+e[i].val<=k)
        dfs(v,x,val+e[i].val,along+1);
    }
}
void calc(int x,int fa,int val,int dep) {
    if(val==k) ans=min(ans,dep),dis[k]=min(dis[k],dep);
    ans=min(ans,dis[k-val]+dep);
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(vis[v]||v==fa) continue;
        if(val+e[i].val<=k) calc(v,x,val+e[i].val,dep+1);
    }
}
void dfs2(int x,int fa,int val) {
    dis[val]=0x3f3f3f3f;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(vis[v]||v==fa)continue;
        if(val+e[i].val<=k) dfs2(v,x,e[i].val+val);
    }
}
void work(int x) {
    top=0;dis[0]=0;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;
        if(vis[v]) continue;
        if(e[i].val<=k)
        calc(v,x,e[i].val,1),dfs(v,x,e[i].val,1);
    }
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]) continue;
        dfs2(v,x,e[i].val);
    }
}
void solve(int x) {
    vis[x]=1;
    work(x);
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].to;rt=0;
        if(vis[v]) continue;
        siz[rt]=size=siz[v];
        barycenter(v,0);
        solve(rt);
    }
}
int main() {
    scanf("%d%d",&n,&k);
    memset(dis,0x3f,sizeof dis);dis[0]=0;ans=n;
    for(int i=1,a,b,c;i<n;i++) {scanf("%d%d%d",&a,&b,&c);add(a+1,b+1,c);add(b+1,a+1,c);}
    size=n,f[0]=n;rt=0;
    barycenter(1,0);
    solve(rt);
    if(ans!=n)cout<<ans;
    else cout<<-1;
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9498640.html
今日推荐