[BZOJ 2599&COGS 2648][IOI2011]Race(点分治)

Description

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

Solution

点分~g[i]存当前的子树中边权和为i的最小边数,h[i]存之前的子树中边权和为i的最小边数

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#define INF 0x3f3f3f3f
#define N 200005
#define K 1000005
typedef long long LL;
using namespace std;
int n,k,ans=INF,mx,tot=0,root=0,tim=0,sign[K],g[K],h[K],vis[N],siz[N],maxv[N],head[N],cnt=0;
vector<int>V;
int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct Node
{
    int next,to,w;
}Edges[N*2];
void addedge(int u,int v,int w)
{
    Edges[cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].to=v;
    Edges[cnt++].w=w;
}
void getroot(int u,int f)
{
    siz[u]=1,maxv[u]=0;
    for(int i=head[u];~i;i=Edges[i].next)
    {
         int v=Edges[i].to;
        if(vis[v]||v==f)continue;
        getroot(v,u);
        siz[u]+=siz[v],maxv[u]=max(maxv[u],siz[v]);
    }
    maxv[u]=max(maxv[u],tot-siz[u]);
    if(maxv[u]<maxv[root])root=u;
}
void getdeep(int u,int f,int d,int c)
{
    if(d>k)return;
    mx=max(mx,d);
    if(sign[d]!=tim)g[d]=c,sign[d]=tim,V.push_back(d);
    else g[d]=min(g[d],c);
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(vis[v]||v==f)continue;
        getdeep(v,u,d+Edges[i].w,c+1);
    }
}
void work(int u)
{
    vis[u]=1,h[0]=0,mx=0;
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(vis[v])continue;
        V.clear();
        tim++,getdeep(v,u,Edges[i].w,1);
        for(int j=0;j<V.size();j++)
        {int t=V[j];ans=min(ans,g[t]+h[k-t]);}
        for(int j=0;j<V.size();j++)
        {int t=V[j];h[t]=min(h[t],g[t]);}
    }
    for(int j=0;j<=mx;j++)h[j]=INF;
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(vis[v])continue;
        root=0,tot=siz[v];
        getroot(v,u),work(root);
    }
}
int main()
{
    n=read(),k=read();
    memset(h,0x3f,sizeof(h));
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
    {
        int u=read()+1,v=read()+1,w=read();
        addedge(u,v,w),addedge(v,u,w);
    }
    maxv[0]=INF,tot=n;
    getroot(1,0),work(root);
    printf("%d\n",ans==INF?-1:ans);
    return 0;
}

 

posted @ 2017-06-04 21:29  Zars19  阅读(162)  评论(0编辑  收藏  举报