HDU

来源:互联网 发布:淘宝erp是什么意思 编辑:程序博客网 时间:2024/06/08 12:11

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 31 2 31 33 42 4
 

Sample Output
355

题意:

有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;}



原创粉丝点击