HDU 5861 Road (线段树) 2016 Multi-University Training Contest 10

Road

Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 165 Accepted Submission(s): 42

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(1≤ai,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

Author
BUPT

Source
2016 Multi-University Training Contest 10

Recommend
wange2014 | We have carefully selected several similar problems for you: 5867 5866 5865 5864 5863

题意:有n个城市,编号1~n。他们之间有一些路1到2,2到3一直下去。n-1条路。每个城市都有一个门,只能开关一次,门在打开时每天都有一个花费。这时候需要运输一些东西,告诉你开始和终止的城市,你需要保证有路径可以到达。最后输出每天的花费即可。
用线段树区间更新维护一下每个城市的最迟可以开门的时间,以及最早可以关门的时间。然后xjb差分统计一下就可以了。

#include "cstring"
#include "cstdio"
#include "iostream"
#include "string.h"
#include "algorithm"
#include "cmath"

#define MAXSIZE 200005

using namespace std;

long long num[100005],ans[MAXSIZE];
int cost[200000];
typedef struct
{
    int left, right,mark,early,late;
    void op(int id)
    {
        mark=1;
        early=min(early,id);
        late=max(late,id);
    }

}NODE;
NODE tree[MAXSIZE * 4];
void build(int root,int lf,int rt)
{
    int mid;
    tree[root].left = lf;
    tree[root].right = rt;
    tree[root].early=0x3f3f3f3f;
    tree[root].late=tree[root].mark=0;
    if (lf == rt)
        return;
    mid = (lf + rt) / 2;
    build(2 * root, lf, mid);
    build(2 * root + 1, mid + 1, rt);
    return;
}
void push_down(int root)
{
    if(tree[root].left==tree[root].right)
        return;
    if(tree[root].mark!=0)
    {
        tree[root*2].op(tree[root].late);
        tree[root*2].op(tree[root].early);
        tree[root*2+1].op(tree[root].late);
        tree[root*2+1].op(tree[root].early);
        tree[root].mark=0;
    }
}
void update(int root,int left,int right,int day)
{
    if(tree[root].left>=left&&tree[root].right<=right)
    {
        tree[root].op(day);
        return;
    }
    push_down(root);
    int mid=(tree[root].left+tree[root].right)/2;
    if(left>mid)
        update(root*2+1, left, right, day);
    else
        if(right<=mid)
            update(root*2,left,right,day);
        else
        {
            update(root*2,left,mid,day);
            update(root*2+1,mid+1,right,day);
        }
}

void dfs(int root)
{
    int l=tree[root].left,r=tree[root].right;
    if(l==r)
    {
        int p=tree[root].early,q=tree[root].late;
        if(p==0x3f3f3f3f||q==0)
            return;
        ans[p]+=cost[l];
        ans[q+1]-=cost[l];
        return;
    }
    push_down(root);
    dfs(root*2);
    dfs(root*2+1);
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n-1;i++)
            scanf("%d",&cost[i]);
        build(1,1,n-1);
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(a>b)
                swap(a,b);
            update(1,a,b-1,i);
        }
        long long sum=0;
        dfs(1);
        for(int i=1;i<=m;i++)
        {
            sum+=ans[i];
            printf("%lld\n",sum);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值