• BZOJ2599 IOI2011Race


    题目:一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小.

    点分治,我们考虑经过根节点的路径,t[x]表示路径长为x时最少的边数,然后每次拿栈记下来清空。

    注意先搜索再更新,这样可以避免同一子树内互相到达。

    By:大奕哥

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=2e5+10,inf=1e9,M=1e6+10;;
     4 int n,k,rt,cnt,head[N],s[N],f[N],t[M],ans,maxn,sta[N],top,dis[N],d[N];
     5 bool v[N];
     6 struct node{
     7     int to,nex,w;
     8 }e[N<<1];
     9 void add(int x,int y,int w)
    10 {
    11     e[++cnt].w=w;e[cnt].nex=head[x];e[cnt].to=y;head[x]=cnt;
    12 }
    13 void getrt(int x,int fa)
    14 {
    15     s[x]=1;f[x]=0;
    16     for(int i=head[x];i;i=e[i].nex)
    17     {
    18         int y=e[i].to;
    19         if(y==fa||v[y])continue;
    20         getrt(y,x);
    21         f[x]=max(f[x],s[y]);
    22         s[x]+=s[y];
    23     }
    24     f[x]=max(f[x],maxn-s[x]);
    25     if(f[x]<f[rt])rt=x;
    26 }
    27 void calc(int x,int fa)
    28 {
    29     if(dis[x]<=k)ans=min(ans,t[k-dis[x]]+d[x]);
    30     for(int i=head[x];i;i=e[i].nex)
    31     {
    32         int y=e[i].to;
    33         if(v[y]||y==fa)continue;
    34         dis[y]=dis[x]+e[i].w;
    35         d[y]=d[x]+1;
    36         calc(y,x);
    37     }
    38 }
    39 void update(int x,int fa)
    40 {
    41     if(dis[x]<=k)t[dis[x]]=min(t[dis[x]],d[x]),sta[++top]=dis[x];
    42     for(int i=head[x];i;i=e[i].nex)
    43     {
    44         int y=e[i].to;
    45         if(v[y]||y==fa)continue;
    46         update(y,x);
    47     }
    48 }
    49 void work(int x)
    50 {
    51     v[x]=1;top=0;t[0]=0;
    52     for(int i=head[x];i;i=e[i].nex)
    53     {
    54         int y=e[i].to;
    55         if(v[y])continue;
    56         dis[y]=e[i].w;d[y]=1;
    57         calc(y,x);
    58         update(y,x);
    59     }
    60     for(int i=1;i<=top;++i)t[sta[i]]=inf;
    61     for(int i=head[x];i;i=e[i].nex)
    62     {
    63         int y=e[i].to;
    64         if(v[y])continue;
    65         maxn=s[y];rt=0;
    66         getrt(y,x);
    67         work(rt);
    68     }
    69 }
    70 int main()
    71 {
    72     scanf("%d%d",&n,&k);
    73     int x,y,w;
    74     for(int i=1;i<n;++i)
    75     {
    76         scanf("%d%d%d",&x,&y,&w);
    77         x++;y++;
    78         add(x,y,w);add(y,x,w);
    79     }
    80     memset(t,0x3f,sizeof(t));
    81     maxn=f[0]=ans=n;
    82     getrt(1,0);
    83     work(rt);
    84     if(ans==n)puts("-1");
    85     else printf("%d
    ",ans);
    86     return 0;
    87 }
  • 相关阅读:
    Pixar 故事公式
    你想住在中国哪里
    tar.gz方式安装nacos设置使用systemct进行service方式的管理并设置开机自启动
    记一个nginx server_name配置多个时的坑
    linux软链接的创建、修改和删除
    阿里云SLB的健康检查配置
    (转载)bullet安装之——windows下的安装与VS开发
    [译] 找到ndarray中的重复行
    [译] 对dataframe数据按照某列值进行分组,分组后连接字符串
    [译] 如何将列表嵌套列表的情况转化成一维列表
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8349406.html
Copyright © 2020-2023  润新知