HDU - 5861 Road(线段树)

本文介绍了一种通过线段树优化路径选择算法的方法,旨在解决一条高速公路上多个村庄间货物运输的问题,目标是最小化总费用。文章详细阐述了如何确定每条路段的开启与关闭时间,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU - 5861

Problem Description
There are n villages along a high way, and divided the high way into n-1 segments. Each segment would charge a certain amount of money for being open for one day, and you can open or close an arbitrary segment in an arbitrary day, but you can open or close the segment for just one time, because the workers would be angry if you told them to work multiple period.

We know the transport plan in the next m days, each day there is one cargo need to transport from village  ai  to village  bi , and you need to guarantee that the segments between  ai  and  bi  are open in the i-th day. Your boss wants to minimize the total cost of the next m days, and you need to tell him the charge for each day.

(At the beginning, all the segments are closed.)
 

Input
Multiple test case. For each test case, begins with two integers n, m(1<=n,m<=200000), next line contains n-1 integers. The i-th integer  wi (1<= wi <=1000) indicates the charge for the segment between village i and village i+1 being open for one day. Next m lines, each line contains two integers  ai,bi(1ai,bi<=n,ai!=bi) .
 

Output
For each test case, output m lines, each line contains the charge for the i-th day.
 

Sample Input
  
  
4 3 1 2 3 1 3 3 4 2 4
 

Sample Output
  
  
3 5 5

题意:

有n个村庄,村庄由n-1条路连接,每条路有一个过路费,只能关和开每条路一次,在接下来的m天里会用到某些线段,必须得保证用到的时候这条路是开的,使总费用最少,求这m天里的每一天的过路费和。

思路:

需要知道每条路开始使用时间和结束使用时间,这个可以用线段树求出来,求出这个之后,把m天当作线段,然后以每条线的过路费为更新的值,比如第i条线开始时间为si,结束时间sj,那么就把[si,sj]都+上val[i],最后来查每一天的总值。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 2e5 + 10,inf = 0x3f3f3f3f;
int start[maxn],stop[maxn];
int tstart[maxn << 2], tstop[maxn << 2];
int value[maxn],val[maxn];
int n,m;

void init()
{
    for(int i = 0; i < (maxn << 2); i++) tstart[i] = inf, tstop[i] = 0;
    for(int i = 0; i <= n; i++) start[i] = inf, stop[i] = 0;
    for(int i = 0; i <= m; i++) value[i] = 0;
}

void pushone(int id)
{
   tstart[id<<1]   = min(tstart[id<<1], tstart[id]);
   tstart[id<<1|1] = min(tstart[id<<1|1], tstart[id]);
   tstart[id] = inf;
}
void pushtwo(int id)
{
   tstop[id<<1]   = max(tstop[id<<1], tstop[id]);
   tstop[id<<1|1] = max(tstop[id<<1|1], tstop[id]);
   tstop[id] = 0;
}
void add(int id,int l,int r,int al,int ar, int val)
{
    if(r < al || l > ar) return;
    if(l >= al && r <= ar)
    {
        tstart[id] = min(tstart[id], val);
        tstop[id]  = max(tstop[id],val);
        return;
    }

    if(tstart[id] != inf) pushone(id);
    if(tstop[id] != 0) pushtwo(id);

    int mid = l+r>>1;
    if(al <= mid) add(id <<  1, l , mid, al, ar, val);
    if(ar >  mid) add(id << 1|1,mid+1,r, al, ar, val);
}
void solve(int id,int l,int r)
{
    if(l == r)
    {
        start[l] = min(tstart[id], start[l]);
        stop[l]  = max(tstop[id], stop[l]);
        return;
    }
    if(tstart[id] != inf) pushone(id);
    if(tstop[id]  != 0)    pushtwo(id);

    int mid = l+r>>1;
    solve(id << 1, l, mid);
    solve(id<<1|1, mid+1,r);
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i = 1; i <= n-1; i++)scanf("%d",&val[i]);
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d",&a,&b);
            if(a > b) swap(a , b);
            add(1,1,n-1,a,b-1,i+1);
        }
        solve(1,1,n-1);
        for(int i = 1; i < n; i++)
        {
            int s = start[i], p = stop[i];
            if(s == inf && p == 0) continue;
            value[s] += val[i], value[p+1] -= val[i];
        }
        for(int i = 1; i <= m; i++) 
        {
            value[i] += value[i-1];
            printf("%d\n", value[i]);
        }
    }
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值