zoukankan      html  css  js  c++  java
  • 洛谷P4149 [IOI2011]Race(点分治)

    题目描述

    给一棵树,每条边有权。求一条简单路径,权值和等于 KK ,且边的数量最小。

    输入输出格式

    输入格式:

     

    第一行:两个整数 n,kn,k 。

    第二至 nn 行:每行三个整数,表示一条无向边的两端和权值 (注意点的编号从 00 开始)。

     

    输出格式:

     

    一个整数,表示最小边数量。

    如果不存在这样的路径,输出 -11 。

     

    输入输出样例

    输入样例#1: 
    4 3
    0 1 1
    1 2 2
    1 3 4
    输出样例#1: 
    2

    说明

    nle 200000,Kle 1000000n200000,K1000000 。

    题解:谁说点分一定要套容斥的?

    这题的暴力思路大约跟dp有点像,每次爆枚到一棵子树中每一个点的距离,显然对于这些距离di,能与他产生解的是之前所有子树中到达距离为k-di的点的最小深度。

    然后就是一遍dfs爆枚所有点,再一遍dfs更新所有最小深度,然后就可以a掉了

    代码如下:

    #include<map>
    #include<set>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define mp make_pair
    #define pii pair<int,int>
    #define inf 0x3f3f3f3f
    using namespace std;
    #define int ll
    typedef long long ll;
    int n,k,deep[2000010],dis[2000010],size[2000010],fa[2000010],vis[2000010];
    int tmp[10000010],ans;
    vector<pii> g[2000100];
    
    void get_size(int now,int f)
    {
        size[now]=1;
        fa[now]=f;
        for(int i=0; i<g[now].size(); i++)
        {
            if(vis[g[now][i].first]||g[now][i].first==f) continue;
            get_size(g[now][i].first,now);
            size[now]+=size[g[now][i].first];
        }
    }
    
    int get_zx(int now,int f)
    {
        if(size[now]==1) return now;
        int son,maxson=-1;
        for(int i=0; i<g[now].size(); i++)
        {
            if(vis[g[now][i].first]||g[now][i].first==f) continue;
            if(size[g[now][i].first]>maxson)
            {
                maxson=size[g[now][i].first];
                son=g[now][i].first;
            }
        }
        int zx=get_zx(son,now);
        while(size[zx]<2*(size[now]-size[zx])) zx=fa[zx];
        return zx;
    }
    
    void calc(int now,int f,int dep,int di)
    {
        deep[now]=dep;
        dis[now]=di;
        if(dis[now]<=k) ans=min(ans,tmp[k-dis[now]]+deep[now]);
        else return;
        for(int i=0; i<g[now].size(); i++)
        {
            if(vis[g[now][i].first]||g[now][i].first==f) continue;
            calc(g[now][i].first,now,dep+1,di+g[now][i].second);
        }
    }
    
    void dfs(int now,int f,int kd)
    {
        if(kd) tmp[dis[now]]=min(tmp[dis[now]],deep[now]);
        else tmp[dis[now]]=inf;
        for(int i=0;i<g[now].size();i++)
        {
            if(vis[g[now][i].first]||g[now][i].first==f) continue;
            dfs(g[now][i].first,now,kd);
        }
    }
    
    void solve(int now)
    {
        vis[now]=1;
        tmp[0]=0;
        for(int i=0;i<g[now].size();i++)
        {
            if(vis[g[now][i].first]) continue;
            calc(g[now][i].first,0,1,g[now][i].second);
            dfs(g[now][i].first,0,1);
        }
        for(int i=0;i<g[now].size();i++)
        {
            if(vis[g[now][i].first]) continue;
            dfs(g[now][i].first,0,0);
        }
        for(int i=0;i<g[now].size();i++)
        {
            if(vis[g[now][i].first]) continue;
            get_size(g[now][i].first,0);
            int zx=get_zx(g[now][i].first,0);
            solve(zx);
        }
    }
    
    main()
    {
        scanf("%lld%lld",&n,&k);
        for(int i=1;i<n;i++)
        {
            int from,to,cost;
            scanf("%lld%lld%lld",&from,&to,&cost);
            g[from+1].push_back(mp(to+1,cost));
            g[to+1].push_back(mp(from+1,cost));
        }
        ans=inf;
        memset(tmp,0x3f,sizeof(tmp));
        solve(1);
        ans==0x3f3f3f3f?puts("-1"):printf("%lld
    ",ans);
    }
  • 相关阅读:
    玩不转云计算的架构
    从《从架构的角度看,如何写好代码?》中来看如何编写单元测试代码
    换种形式工作
    程序员下一门要学的编程语言Swift
    从钉钉微应用定制化导航栏看如何实现Hybrid App开发框架
    纯灌水Linus主义
    kFreeBSD有活过来的迹象?UbuntuBSD
    架构的重要性
    MacOS下如何进行Git的冲突(Conflict)处理
    [转]以Facebook为案例剖析科技公司应有的工具文化
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9432824.html
Copyright © 2011-2022 走看看