HDU 5861 Road 线段树区间更新单点查询

题目链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5861

Road

Time Limit: 12000/6000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)

问题描述

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.)

输入

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).

输出

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条路,每条路开启的花费是a[i]每天,你可以选择每条路的开启时间和关闭时间,但是路关闭之后就不能再开启。现在告诉你接下来的m天的行程,每天会有一辆货车从u到v,你需要保证货车经过的道路必须是开启的。问每天的最小花费。

题解

用线段树求出使用到每条道路的最早时间和最晚时间(这就是我们需要设置的开启时间和关闭时间了)。然后以天数作为数组,再建一颗线段树,根据没条道路的开放时间[mi,ma]去区间更新,然后单点查询求每一天的花费是多少。

代码

这里用的是一种不需要打懒惰标记的方法,并且由于是单点查询,所以只需要往下更新,不用回溯回来。

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)

typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=2e5+10;

int road[maxn];

//这里maxv,minv是一颗线段树,sumv是另一颗线段树,偷懒写在一起了
int maxv[maxn<<2],minv[maxn<<2];
int sumv[maxn<<2];

int ql,qr,_v,_v2;
void update(int o,int l,int r,int type) {
    if(ql<=l&&r<=qr) {
        if(type==-1) {
            maxv[o]=max(maxv[o],_v);
            minv[o]=min(minv[o],_v);
        } else {
            sumv[o]+=_v2;
        }
    } else {
        if(ql<=mid) update(lson,l,mid,type);
        if(qr>mid) update(rson,mid+1,r,type);
    }

}

int _p,_ma,_mi,_sum;
void query(int o,int l,int r,int add,int ma,int mi) {
    if(l==r) {
        _ma=max(ma,maxv[o]);
        _mi=min(mi,minv[o]);
        _sum=add+sumv[o];
    } else {
        if(_p<=mid) query(lson,l,mid,add+sumv[o],max(ma,maxv[o]),min(mi,minv[o]));
        else query(rson,mid+1,r,add+sumv[o],max(ma,maxv[o]),min(mi,minv[o]));
    }
}

void init() {
    clr(sumv,0);
    clr(maxv,-1);
    clr(minv,0x3f);
}

int main() {
    int n,m;
    while(scanf("%d%d",&n,&m)==2&&n) {
        init();
        for(int i=1; i<=n-1; i++) scanf("%d",&road[i]);

        ///求每条路开放的最早和最迟时间
        for(int i=1; i<=m; i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u>v) swap(u,v);
            v--;
            ql=u,qr=v,_v=i;
            update(1,1,n-1,-1);
        }
        for(int i=1; i<=n-1; i++) {
            _p=i,_ma=-1,_mi=INF;
            query(1,1,n-1,0,_ma,_mi);
            //			printf("%d,%d\n",_mi,_ma);
            if(_mi>_ma) continue;
            ql=_mi,qr=_ma,_v2=road[i];
            update(1,1,m,1);
        }
            
            ///求每天的花费是多少
        for(int i=1; i<=m; i++) {
            _p=i,_sum=0;
            query(1,1,m,0,_ma,_mi);
            printf("%d\n",_sum);
        }
    }
    return 0;
}

//end-----------------------------------------------------------------------
posted @ 2016-08-18 20:48  fenicnn  阅读(356)  评论(0编辑  收藏  举报