zoukankan      html  css  js  c++  java
  • 2599: [IOI2011]Race

    2599: [IOI2011]Race

    Time Limit: 70 Sec  Memory Limit: 128 MB
    Submit: 3088  Solved: 905
    [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

    HINT

     

    Source

     
    [Submit][Status][Discuss]

    这题有点怪的点分治。。。

    我的做法也比较逗,就是开一个100W的数组t,t[i]表示权值为i的路径最少边数

    找到重心分成若干子树后, 得出一棵子树的所有点到根的权值和x,到根a条边,用t[k-x]+a更新答案,全部查询完后

    然后再用所有a更新t[x]

    这样可以保证不出现点分治中的不合法情况

    把一棵树的所有子树搞完后再遍历所有子树恢复T数组,如果用memset应该会比较慢

    orz hzwer!

    #include<cstdio>
    #include<iostream>
    #pragma GCC optimize("O2")
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=2e5+5,M=1e6+5;
    int n,K,tot,sum,root,ans;
    int t[M],head[N],son[N],f[N],dis[N],d[N];
    bool vis[N];
    struct node{
        int v,w,next;
    }e[N<<1];
    void ins(int x,int y,int z){
        e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
        e[++tot].v=x;e[tot].w=z;e[tot].next=head[y];head[y]=tot;
    }
    void getroot(int x,int fa){
        son[x]=1;f[x]=0;
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]&&v!=fa){
                getroot(v,x);
                son[x]+=son[v];
                f[x]=max(f[x],son[v]);
            }
        }
        f[x]=max(f[x],sum-son[x]);
        if(f[x]<f[root]) root=x;
    }
    void cal(int x,int fa){
        if(dis[x]<=K) ans=min(ans,d[x]+t[K-dis[x]]);
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]&&v!=fa){
                d[v]=d[x]+1;
                dis[v]=dis[x]+e[i].w;
                cal(v,x);
            }
        }
    }
    void add(int x,int fa,bool flag){
        if(dis[x]<=K){
            if(flag) t[dis[x]]=min(t[dis[x]],d[x]);
            else t[dis[x]]=1e9;
        }
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]&&v!=fa){
                add(v,x,flag);
            }
        }
    }
    void work(int x){
        vis[x]=1;t[0]=0;
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]){
                d[v]=1;
                dis[v]=e[i].w;
                cal(v,0);
                add(v,0,1);
            }
        }
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]){
                add(v,0,0);
            }
        }
        for(int i=head[x],v;i;i=e[i].next){
            if(!vis[v=e[i].v]){
                root=0;
                sum=son[v];
                getroot(v,0);
                work(root);
            }
        }
    }
    int main(){
        n=read();K=read();
        for(int i=1;i<=K;i++) t[i]=n;
        for(int i=1,x,y,z;i<n;i++){
            x=read();y=read();z=read();
            ins(x+1,y+1,z);
        }
        ans=sum=f[0]=n;
        getroot(1,0);
        work(root);
        printf("%d
    ",ans!=n?ans:-1);
        return 0;
    }
  • 相关阅读:
    Java之IO流
    Servlet中Session的用法
    Servlet中Cookie的用法
    HTML的表单元素和input元素
    Servlet第一个实例之用户登录网址
    Servlet的生命周期和三种实现方式
    写一下近期的计划(工作)
    RxJava的基础知识
    actionbar、toolbar、menu之间的关系
    ButterKnife的基础知识
  • 原文地址:https://www.cnblogs.com/shenben/p/6295976.html
Copyright © 2011-2022 走看看