[codeforces] Gym - 100814D Frozen Rivers (BFS + 二分)

5 篇文章 0 订阅
3 篇文章 0 订阅

[codeforces] Gym - 100814D Frozen Rivers (BFS + 二分)


题目链接:Gym - 100814D Frozen Rivers
题目大意:
n 个点, 之后2...n行输入, 每行有一个 pi,ci 表示 i 的父节点以及两点之间的边权。生成一棵树, 树从根节点开始融化, 每秒1单位长度当的速度,当到达第一个儿子节点, 到达其他儿子节点的速度变为 0.5 单位长度每秒。
之后由 q 个询问, 每次询问一个时间ci, 问以到当前时刻共有多少叶子节点融化。
数据范围:
(1<=n<=1e5)(1<=pi<=n)(0<=ci<=1e5)
(1<=q<=1e5)0<=qi<=1e12)

解题思路:
这道题就是题意有点不好懂,, 懂了之后还是挺好写的, BFS可以求出到达每个点的时间, 对于叶子节点单独存起来。 之后的每个询问都可以二分去查找。
代码:

//2017-08-07 10:25
//2017-08-07 11:02
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int MaxN = 1e5;
int n, m, seq[MaxN + 5], cnt, tot, T;
int all, pre[2 * MaxN + 5], last[MaxN + 5], other[2 * MaxN + 5];
LL ans[MaxN + 5], cost[2 * MaxN + 5], t[MaxN + 5];
bool vis[MaxN + 5];
struct Node {
    LL s; int v;
}p[MaxN + 5];
bool cmp(Node a, Node b){ return a.s < b.s; }

void build(int u, int v, LL w){
    pre[++all] = last[u];
    last[u] = all;
    other[all] = v;
    cost[all] = w;
}

void Bfs(){
    memset(vis, 0, sizeof(vis));
    int head = 1, tial = 0;
    seq[++tial] = 1, vis[1] = true, t[1] = 0;
    while(head <= tial){
        int now = seq[head];
        int ed = last[now];
        tot = 0;
        while(ed != -1){
            int dr = other[ed];
            if(!vis[dr]){
                vis[dr] = true;
                seq[++tial] = dr;
                p[++tot].v = dr;
                p[tot].s = cost[ed];
            }
            ed = pre[ed];
        }
        if(tot == 0) ans[++cnt] = t[now];
        else{
            sort(p + 1, p + 1 + tot, cmp);
            t[p[1].v] = t[now] + p[1].s;
            for(int i= 2; i <= tot; i++) 
                t[p[i].v] = t[now] + p[1].s + (p[i].s - p[1].s) * 2;
        }
        head++;
    }
}

int main(){
    scanf("%d", &T);
    while(T--){
        all = -1, memset(last, -1, sizeof(last));
        scanf("%d", &n);
        for(int i = 2; i <= n; i++){
            int u; LL w;
            scanf("%d %lld", &u, &w);
            build(i, u, w);
            build(u, i, w);
        }
        cnt = 0;
        Bfs();
        sort(ans + 1, ans + 1 + cnt);
        scanf("%d", &m);
        while(m--){
            LL x;
            scanf("%lld", &x);
            int l = 1, r = cnt, res = 0, mid;
            while(l <= r){
                mid = (l + r) >> 1;
                if(ans[mid] <= x) res = mid, l = mid + 1;
                else r = mid - 1;
            }
            printf("%d\n", res);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值