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