• BZOJ_2599_[IOI2011]Race_点分治


    BZOJ_2599_[IOI2011]Race_点分治

    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


    点分治。开个桶记录一下长度为x的路径最小的深度。

    如何去重?我们开一个辅助桶存一下根的当前儿子的子树内的贡献。

    保证每次查的时候用的是其他儿子的子树的路径。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 200050
    #define inf 100000000
    int head[N],to[N<<1],nxt[N<<1],cnt,val[N<<1];
    int root,sum,siz[N],f[N],g[1000050],d[N],n,k,ans,dep[N],tmp[1000050],a[N],b[N];
    bool used[N];
    inline void add(int u,int v,int w) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
    }
    void get_root(int x,int y) {
        siz[x]=1; f[x]=0;
        int i;
        for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
            get_root(to[i],x);
            siz[x]+=siz[to[i]];
            f[x]=max(f[x],siz[to[i]]);
        }
        f[x]=max(f[x],sum-siz[x]);
        if(f[x]<f[root]) root=x;
    }
    void get_dep(int x,int y) {
        b[++b[0]]=x;
        a[++a[0]]=x;
        siz[x]=1;
        dep[x]=dep[y]+1;
        //printf("x=%d dep[x]=%d
    ",x,dep[x]);
        if(d[x]<=k) {
            ans=min(ans,g[k-d[x]]+dep[x]-2);
            tmp[d[x]]=min(tmp[d[x]],dep[x]);
        }
        int i;
        for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
            d[to[i]]=d[x]+val[i];
            get_dep(to[i],x);
            siz[x]+=siz[to[i]];
        }
    }
    void work(int x) {
        g[0]=1;
        used[x]=1;
        d[x]=0;
        int i,j;
        b[0]=0;
        siz[x]=1;
        dep[x]=1;
        for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
            a[0]=0;
            d[to[i]]=val[i];
            get_dep(to[i],x);
            siz[x]+=siz[to[i]];
            for(j=1;j<=a[0];j++) if(d[a[j]]<=k) {
                g[d[a[j]]]=min(g[d[a[j]]],tmp[d[a[j]]]);
            }
            for(j=1;j<=a[0];j++) if(d[a[j]]<=k) tmp[d[a[j]]]=inf;
        }
        for(i=1;i<=b[0];i++) if(d[b[i]]<=k) {
            g[d[b[i]]]=tmp[d[b[i]]]=inf;
        }
        g[0]=tmp[0]=inf;
        for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
            root=0;
            sum=siz[to[i]];
            get_root(to[i],0);
            work(root);
        }
    }
    int main() {
        scanf("%d%d",&n,&k);
        int i,x,y,z;
        for(i=0;i<=k;i++) g[i]=tmp[i]=inf;
        for(i=1;i<n;i++) {
            scanf("%d%d%d",&x,&y,&z);
            x++;y++;
            add(x,y,z);add(y,x,z);
        }
        sum=n;
        f[0]=inf;
        ans=1<<30;
        root=0;
        get_root(1,0);
        work(root);
        printf("%d
    ",ans>n?-1:ans);
    }
    
  • 相关阅读:
    PPT能输英文不能输汉字
    常用HTML正则表达式
    Log4j使用总结
    JsonConfig过滤对象属性
    打开”我的电脑“,不显示”共享文档“和”我的文档“,解决办法。(windows XP系统)
    错误org.hibernate.LazyInitializationException
    Tomcat中实现IP访问限制
    windows server 2008中让AD域中的普通用户可以 远程登录 域控服务器。
    ibatis简介及 like查询
    IE访问页面的时候,受限制的解决方案。
  • 原文地址:https://www.cnblogs.com/suika/p/8743225.html
Copyright © 2020-2023  润新知