P4149 [IOI2011] Race——點分治 模板

Glowingfire發表於2024-11-05

[IOI2011] Race

題目描述

給一棵樹,每條邊有權。求一條簡單路徑,權值和等於 \(k\),且邊的數量最小。

輸入格式

第一行包含兩個整數 \(n,k\),表示樹的大小與要求找到的路徑的邊權和。

接下來 \(n-1\) 行,每行三個整數 \(u_i,v_i,w_i\),代表有一條連線 \(u_i\)\(v_i\),邊權為 \(w_i\) 的無向邊。

注意:點從 \(0\) 開始編號

輸出格式

輸出一個整數,表示最小邊數量。

如果不存在這樣的路徑,輸出 \(-1\)

樣例 #1

樣例輸入 #1

4 3
0 1 1
1 2 2
1 3 4

樣例輸出 #1

2

提示

對於 \(100\%\) 的資料,保證 \(1\leq n\leq 2\times10^5\)\(0\leq k,w_i\leq 10^6\)\(0\leq u_i,v_i<n\)

codes

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
const int INF=1e6+100;
struct edge
{
    int y,n,z;
}e[N<<1];
int n,m,head[N],cnt;
int siz[N],root,all,mxa[N];
int qu[N],bi[N],uq[N],tot[INF],ed[N],ans=INF;
bool vis[N];
long long dis[N];
void ad(int x,int y,int z)
{
    e[++cnt].n=head[x];
    e[cnt].y=y;
    e[cnt].z=z;
    head[x]=cnt;
}

void getrt(int u,int fa)
{
    siz[u]=1;mxa[u]=0;
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(v==fa || vis[v])continue;
        getrt(v,u);
        siz[u]+=siz[v];
        mxa[u]=max(mxa[u],siz[v]);
    }
    mxa[u]=max(all-siz[u],mxa[u]);
    if(mxa[u]<mxa[root])root=u;
}

void getdis(int u,int fa,int d)
{
    if(dis[u]<=m)
    {
        qu[++qu[0]]=dis[u];
        bi[qu[0]]=d;
    }
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(v==fa || vis[v])continue;
        dis[v]=dis[u]+e[i].z;
        getdis(v,u,d+1);
    }

}

void calc(int u)
{
    int num=0;
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(vis[v])continue;

        qu[0]=0;
        dis[v]=e[i].z;
        getdis(v,0,1);

        for(int j=1;j<=qu[0];++j)
            if(qu[j]<=m)
            ans=min(tot[m-qu[j]]+bi[j],ans);
        for(int j=1;j<=qu[0];++j)
        {
            ++num;
            uq[num]=qu[j];
            tot[qu[j]]=min(tot[qu[j]],bi[j]);
        }
    }
    for(int i=1;i<=num;++i)
        tot[uq[i]]=INF;
}

void solve(int nw)
{
    vis[nw]=1;
    calc(nw);
    for(int i=head[nw];i;i=e[i].n)
    {
        int v=e[i].y;
        if(vis[v])continue;
        root=0;
        mxa[root]=INF;
        all=siz[v];
        getrt(v,0);
        solve(root);
    }
}

void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y,z;i<n;++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        ++x;++y;
        ad(x,y,z);ad(y,x,z);
    }
    for(int i=1;i<=m;++i)
        tot[i]=INF;
}

void work()
{
    all=n;
    mxa[root]=INF;
    getrt(1,0);
    solve(root);
    if(ans==INF)cout<<-1;
    else cout<<ans;
}
int main()
{
    init();
    work();
    return 0;
}

相關文章