zoukankan      html  css  js  c++  java
  • [BZOJ2599][IOI2011]Race 点分治

    2599: [IOI2011]Race

    Time Limit: 70 Sec  Memory Limit: 128 MB
    Submit: 3934  Solved: 1163
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

    一个整数 表示最小边数量 如果不存在这样的路径 输出-1

    Sample Input

    4 3
    0 1 1
    1 2 2
    1 3 4

    Sample Output

    2
     
     
    考虑点分治,每次对子树进行dfs求出子树中每个点到根的距离并记在dis[i]中,步数记在b[i]中。
    同时我们开一个桶tot,记录这颗子树之前的子树中所有dis中步数的最小值。
    开一个v的桶记录此时tot桶中记录的数是否为以当前u为根更新的答案。
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 using namespace std;
     7 struct data {
     8     int to,next,val;
     9 }e[400005];
    10 int head[200005],cnt;
    11 bool vis[200005];
    12 void add(int u,int v,int val) {e[cnt].to=v;e[cnt].next=head[u];e[cnt].val=val;head[u]=cnt++;}
    13 int son[200005],f[200005],root,sum;
    14 int b[200005],dis[200005],tot[1000005];
    15 int n,k;
    16 int ans=0;
    17 int num;
    18 int v[1000005];
    19 int tt=0;
    20 void findroot(int x,int fa) {
    21     son[x]=1;f[x]=0;
    22     for(int i=head[x];i>=0;i=e[i].next) {
    23         int to=e[i].to;if(to==fa||vis[to]) continue;
    24         findroot(to,x);
    25         son[x]+=son[to];
    26         f[x]=max(f[x],son[to]);
    27     }
    28     f[x]=max(f[x],sum-son[x]);
    29     if(f[x]<f[root]) root=x;
    30     return;
    31 }
    32 void dfs(int x,int fa,int d,int dep) {
    33     dis[++num]=d;b[num]=dep;
    34     for(int i=head[x];i>=0;i=e[i].next) {
    35         int to=e[i].to;if(to==fa||vis[to]) continue;
    36         if(d+e[i].val>k) continue;
    37         dfs(to,x,d+e[i].val,dep+1);
    38     }
    39 }
    40 void work(int x) {
    41     vis[x]=1;
    42     bool flag=0;
    43     for(int i=head[x];i>=0;i=e[i].next) {
    44         num=0;
    45         int to=e[i].to;if(vis[to]) continue;
    46         if(e[i].val>k) continue;
    47         dfs(to,x,e[i].val,1);
    48         for(int j=1;j<=num;j++) if(dis[j]==k) ans=min(ans,b[j]);
    49         if(flag)
    50             for(int j=1;j<=num;j++) 
    51                 if(dis[j]<=k&&v[k-dis[j]]==x) ans=min(ans,b[j]+tot[k-dis[j]]);
    52         for(int j=1;j<=num;j++) 
    53             if(dis[j]<=k) {
    54                 if(v[dis[j]]!=x) v[dis[j]]=x,tot[dis[j]]=b[j];
    55                 else tot[dis[j]]=min(tot[dis[j]],b[j]);
    56             }
    57         flag=1;
    58     }
    59     for(int i=head[x];i>=0;i=e[i].next) {
    60         int to=e[i].to;
    61         if(vis[to]) continue;
    62         root=0;f[0]=n;sum=son[to];
    63         findroot(to,x);
    64         work(root);
    65     }
    66 }
    67 int main() {
    68     //freopen("gg.in","r",stdin);
    69     memset(head,-1,sizeof(head));
    70     scanf("%d%d",&n,&k);
    71     for(int i=1;i<n;i++) {
    72         int u,v,t;
    73         scanf("%d%d%d",&u,&v,&t);
    74         add(u+1,v+1,t);add(v+1,u+1,t);
    75     }
    76     sum=n;ans=n;f[0]=n;
    77     findroot(1,0);
    78     work(root);
    79     if(ans==n) printf("-1");
    80     else printf("%d",ans);
    81 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    Windows Service开发介绍
    解决Vuex持久化插件-在F5刷新页面后数据不见的问题
    selenium+python 安装使用
    字符串拆分姓名、电话、省市区逻辑
    常用正则表达式大全——包括校验数字、字符、特殊密码过滤
    uni-app 地图初用 map
    前端常见手写笔试题
    数组去重和排序
    js获取当前时间年份,处理年月日
    js循环匹配组合成新对象或js循环组合新数据
  • 原文地址:https://www.cnblogs.com/wls001/p/7756381.html
Copyright © 2011-2022 走看看