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

  

猜你喜欢

转载自www.cnblogs.com/pkgunboat/p/10670101.html