Codeforces 1137E 凸包
题意:有一辆火车,初始只有一个车厢,权值为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)); } }