HDU5380——单调队列——Travel with candy

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

/*
双端队列
题意:加油问题,从起始到终点。,每走一步需要消耗1L油,中途可以买卖油,有一个最大油量,问你到达终点的最少花费是多少
用一个双端队列维护


*/
/************************************************
* Author        :Powatr
* Created Time  :2015-8-17 18:28:49
* File Name     :HDU5380.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;

int n, c;
int buy[MAXN*2], sell[MAXN*2];
int a[MAXN];
struct P{
    int val, num;
}q[MAXN];
ll ans;
int l, r;
int cnt;
void MAX(int x)
{
    //把所有买的价格小于x的油都用x卖出
    int sum = 0;
    while(l <= r && x > q[l].val){
        sum += q[l].num;
        l++;
    }
    if(sum){
        q[--l].num = sum;
        q[l].val = x;
    }
}

void MIN(int x)
{
    //把所有卖的价格大于x的油都用x买入
    while(l <= r && x < q[r].val){
        ans -= 1ll * q[r].val * q[r].num;
        cnt += q[r].num;
        r--;
    }
}

int DEL(int x)
{
    //路上所要消耗的油
    while(x){
        int v = min(x, q[l].num);
        q[l].num -= v;
        x -= v;
        if(q[l].num == 0) l++;
    }
}

int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &c);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = 0; i <= n; i++)
            scanf("%d%d", &buy[i], &sell[i]);
        ans = 0;
         l = r = n;
        r--;
        for(int i = 0; i < n; i++){
            MAX(sell[i]);
            cnt = (i == 0 ? c : a[i] - a[i-1]);//所需要的油
            MIN(buy[i]);
            r++;
            q[r].val = buy[i];
            q[r].num = cnt;
            ans += 1ll * cnt * buy[i];//把油装满所需要的钱
            DEL(a[i+1] - a[i]);
        }
      MAX(sell[n]);
      for(int i = l; i <= r; i++)
          ans -= 1ll * q[i].val * q[i].num;
      printf("%I64d\n", ans);
    }
    return 0;
}

  

posted @ 2015-08-17 19:24  Painting、时光  阅读(180)  评论(0编辑  收藏  举报