题意:有一辆火车,初始只有一个车厢,权值为0。有3种操作:
1:在火车头前面加若干辆车
2:在火车车尾加若干辆车
3:每个车的权值加上b + (i - 1) * s,其中i是指这节车厢是从头算的第几个车厢。
每次操作后,询问离火车头最近的权值最小的车厢。
思路:看这篇博客就行了,实现方式比较巧妙。
代码:
#include <bits/stdc++.h>
#define db long long
#define LL long long
using namespace std;
const int maxn = 500010;
const double eps = 1e-9;
int top;
LL b[maxn], s[maxn];
struct point {
db x, y;
point(){};
point(db _x, double _y) :x(_x), y(_y){};
};
point st[maxn];
int n;
LL cal(point x, int now) {
return b[now] - b[x.y] + (x.x - 1) * (s[now] - s[x.y]);
}
LL mul(LL x, LL y, LL x1, LL y1) {
return x * y1 - x1 * y;
}
void add(LL x, LL y) {//x 实际位置 y 读入次序
if(cal(st[top], y) == 0) return;
LL tmp = cal(point(x, y), y);
while(top >= 2) {
if(mul(st[top].x - st[top - 1].x, cal(st[top], y) - cal(st[top - 1], y), x - st[top].x, tmp - cal(st[top], y)) > 0) break;
top--;
}
st[++top] = point(x, y);
}
void del(int x) {
while(top >= 2 && cal(st[top], x) >= cal(st[top - 1], x))
top--;
}
int main() {
int n, m, op;
LL x, y;
scanf("%d%d", &n, &m);
st[++top] = point(1, 0);
for (int i = 1; i <= m; i++) {
b[i] = b[i - 1];
s[i] = s[i - 1];
scanf("%d", &op);
if(op == 1) {
scanf("%lld", &x);
b[i] = s[i] = 0;
st[top = 1] = point(1, i);
n += x;
} else if(op == 2) {
scanf("%lld", &x);
add(n + 1, i);
n += x;
} else {
scanf("%lld%lld", &x, &y);
b[i] += x;
s[i] += y;
del(i);
}
printf("%lld %lld\n", st[top].x, cal(st[top], i));
}
}