【BZOJ 2216】【POI 2011】Lightning Conductor

http://www.lydsy.com/JudgeOnline/problem.php?id=2216
学习了一下决策单调性。
这道题决策单调性比较明显,不详细证了。
对于一个决策i,如果在i之前的j处进行决策,那么i之后的决策都不可能在j之前。
利用决策单调性,可以维护每个决策点形成的单调栈,更新决策点也是利用单调栈的信息在原数组上二分。
这道题假设j<i,然后扫两遍就可以了,时间复杂度\(O(n\log n)\)
看网上的大爷都写得单调队列?整体二分?orz

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 500003;

int st[N], top, stn[N];

void solve(int n, int *a, int *f) {
	top = 0;
	for (int i = 1; i <= n; ++i) {
		int left = 1, right = top, mid;
		while (left < right) {
			mid = (left + right + 1) >> 1;
			if (stn[mid] <= i) left = mid;
			else right = mid - 1;
		}
		
		if (top) f[i] = max(ceil(sqrt(i - st[left])) + a[st[left]] - a[i], 0.0);
		while (top && stn[top] > i && sqrt(stn[top] - st[top]) + a[st[top]] < sqrt(stn[top] - i) + a[i]) --top;
		
		if (!top) {st[++top] = i; stn[top] = i + 1; continue;}
		
		left = max(i + 1, stn[top] + 1); right = n + 1;
		while (left < right) {
			mid = (left + right) >> 1;
			if (sqrt(mid - st[top]) + a[st[top]] < sqrt(mid - i) + a[i]) right = mid;
			else left = mid + 1;
		}
		
		if (left <= n) st[++top] = i, stn[top] = left;
	}
}

int a[N], n, f1[N], f2[N];

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) scanf("%d", a + i);
	solve(n, a, f1);
	reverse(a + 1, a + n + 1);
	solve(n, a, f2);
	reverse(f2 + 1, f2 + n + 1);
	
	for (int i = 1; i <= n; ++i) printf("%d\n", max(f1[i], f2[i]));
	return 0;
}
posted @ 2017-04-06 19:21  abclzr  阅读(329)  评论(0编辑  收藏  举报