ZOJ 3724 Delivery(树状数组+离线处理)

题意:

N个点,对于每个点i,都有一条连向i+1的有向边,另外有M条其他的有向边(姑且称作小道边),有Q个询问 (u,v) u v的最短路。

解析:

这题真的是思考了好久,也参考了很多大牛的博客,终于把这题给过了。
这题让我理解到了,原来树状数组也可以维护最大值和最小值,真的是长见识了。

以下解析,可能是这题网络上最详细的讲解了。

刚一看感觉是最短路的题,但是再一想,有 n1 条有向边,你可以随意用但是那些小道边,且只可以用一次,所以就是对于特定的问题,根据那些小道边对于每个点的距离进行更新。

为了防止读者在阅读的过程中出现混乱,先定义如下变量

  1. (u,v) 表示每条询问边
  2. (u,v) 表示每条小道边
  3. dist(u,v) 表示 u->v 城市之间,没有经过小道边的距离。
  4. cost(u,v) 表示当前这条小道边(u, v)的权值

首先可以预处理出前缀和 sum 数组,这样方便询问 (u,v) 之间的距离。

对于 u<v u>v 的这两种情况,则需要进行分类讨论。

(1) 对于 u<v 的这种情况,即 u>v 的情况
可以首先可以得到的两点间的距离为 dist(u,v)=sum[v]sum[u]

那么要求 u>v 最小的解,就是求一些小道边可以节省最大路程是多少的,因为那些小道只可以用一次,所以对这个结果产生影响的只有小道边 (u,v) ,其中 u<=u<v<=v

可以对于所有询问,和所有小道边进行离散处理,并一块进行排序。
可以对于 (u,v) 这条边 u 大的排前,如果u一样的那么 v 小的排前。
这样就可以保证在查询到 (u,v) 之前,所有的 (u,v) u<=u<v<=v 都已经插入好,
同时,对于小道边 (u,v) u<u 或者 u=uv>v 的这样的边还没插入。

然后对于一个小道边,则对1 到 u’ 进行更新,更新的值为
dist(u,v)cost(u,v)=(sum[v]sum[u])cost(v,u)
代表这条边对于这个区间内可以节省的最大的值,

对于每次询问,则直接在线段树中查找在u的位置的最大值,那么总距离就最小,结果为
dist(u,v)query(v)=sum[v]sum[u]query(v)

(2) 对于 u>v 这种情况,即 v>u 的情况
类似于上面的分析,对于询问 (u,v)
因为只有一个小道可以选择,那么对其产生影响的边只有 u v ,其中 v<=v<u<=u

首先进行同 (1) 的一样的排序,这样保证了在查询到 (u,v) 之前,所有 (u,v) v<=v<u<=u 的都已经插入好,
同时, (u,v) v<v<u<u 那些情况不能插入。

所以对于每次询问 v>u ,插入每条小道边 v>u ,之后的边长为
dist(v,u)+cost(v,u)dist(v,u)=(sum[u]sum[v])+cost(v,u)(sum[u]sum[v])

由于 dist(v,u) 是个定值,所以在询问的时候 dist(v,u) 是不起作用的,相当于一个常数,我们需要的只是 dist(v,u)+cost(v,u) 最小,这样才能使得总路程最小,所以更新的时候只需要维护这个就好了。

然后对于一个小道边,则对1 到 v’ 进行更新,更新的值为 dist(v,u)+cost(v,u)
对于每次询问,则直接在线段树中查找在v的位置的最小值,那么总距离就最小,
结果为 query(v)dist(u,v)

至此圆满结束。

注意:

注意虽然题目说最终结果不会超过int,但是中间过程可能会爆int,所以要开long long。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll INF = (1LL<<63)-1;
const int N = 100005;
const int M = 400005;
int n, m, q;

struct Edge {
    int kind, id;
    int u, v;
    ll cost;
} arr[M];
int top;

ll ans[M], sum[N];

struct BIT {
    ll C[N];
    void clear(ll val) { fill(C, C+N, val); }

    inline int lowbit(int x) { return x & (-x); }

    ll query(int x) {
        ll ret = INF;
        while(x > 0) {
            ret = min(ret, C[x]);
            x -= lowbit(x);
        }
        return ret;
    }

    void update(int x, ll val) {
        while(x <= n) {
            C[x] = min(C[x], val);
            x += lowbit(x);
        }
    }
} bit;

bool cmp(Edge a, Edge b) {
    if(a.u != b.u)
        return a.u > b.u;
    else {
        if(a.kind != b.kind)
            return a.kind < b.kind;
        return a.v < b.v;
    }
}

void prepare() {
    int u, v;
    ll cost;
    sum[0] = sum[1] = 0;
    for(int i = 2; i <= n; i++) {
        scanf("%lld", &sum[i]);
        sum[i] += sum[i-1];
    }

    top = 0;
    for(int i = 0; i < m; i++) {
        scanf("%d%d%lld", &u, &v, &cost);
        arr[top].kind = 0;
        arr[top].u = u, arr[top].v = v, arr[top].cost = cost;
        top++;
    }

    scanf("%d", &q);
    for(int i = 0; i < q; i++) {
        scanf("%d%d", &u, &v);
        arr[top].kind = 1;
        arr[top].u = u, arr[top].v = v, arr[top].id = i;
        top++;
    }
    sort(arr, arr+top, cmp);
}

void solve() {
    int u, v, kind, id;
    ll cost;

    memset(ans, 0, sizeof(ans));
    bit.clear(0);
    for(int i = 0; i < top; i++) {
        u = arr[i].u, v = arr[i].v, kind = arr[i].kind;
        if(u < v && kind == 0) {
            cost = arr[i].cost;
            bit.update(v, cost - (sum[v] - sum[u]));
        }else if(u < v && kind == 1) {
            id = arr[i].id;
            ans[id] = bit.query(v) + (sum[v] - sum[u]);
        }
    }

    bit.clear(INF);
    for(int i = 0; i < top; i++) {
        u = arr[i].u, v = arr[i].v, kind = arr[i].kind;
        if(u > v && kind == 0) {
            cost = arr[i].cost;
            bit.update(v, (sum[u] - sum[v]) + cost);
        }else if(u > v && kind == 1) {
            id = arr[i].id;
            ans[id] = bit.query(v) - (sum[u] - sum[v]);
        }
    }
}

void output() {
    for(int i = 0; i < q; i++)
        printf("%lld\n", ans[i]);
}

int main() {
    while(~scanf("%d%d", &n, &m)) {
        prepare();
        solve();
        output();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值