【BZOJ3827】[Poi2014]Around the world【尺取法】【并查集】

【题目链接】

对于每个询问,设油量为d。

先预处理出每个点走一次最多走到哪,这个用尺取法可以O(n)。

然后得到一颗树,算一下每个点的深度。

枚举起点,在树上一直向上爬,直到距离超过n,爬的过程同时用并查集合并。


傻逼题卡内存。

/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 1000005, inf = 0x7FFFFFFF;

int n, m, dis[maxn], next[maxn << 1], depth[maxn << 1];

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}

inline int solve(int x) {
	int fa = x;
	for(; fa < x + n; fa = next[fa]);
	for(int i = next[x], j = x; i != fa; j = i, i = next[i]) next[j] = fa;
	return depth[x] - depth[fa];
}

int main() {
	n = iread(); m = n << 1;
	int k = iread(), lwb = 0;
	for(int i = 1; i <= n; i++) {
		dis[i] = iread();
		lwb = max(lwb, dis[i]);
	}
	while(k--) {
		int d = iread();
		if(d < lwb) {
			printf("NIE\n");
			continue;
		}
		for(int i = 1, j = 1, sum = 0; i <= m; i++) {
			while(j < m)
				if(sum + dis[j > n ? j - n : j] <= d) {
					sum += dis[j > n ? j - n : j];
					j++;
				}
				else break;
			sum -= dis[i > n ? i - n : i];
			next[i] = j;
		}
		depth[m] = 0;
		for(int i = m; i >= 1; i--) depth[i] = depth[next[i]] + 1;
		int ans = inf;
		for(int i = 1; i <= n; i++) ans = min(ans, solve(i));
		printf("%d\n", ans);
	}
	return 0;
}


你可能感兴趣的:(【BZOJ3827】[Poi2014]Around the world【尺取法】【并查集】)