一道有点意思的题。
看到是一个环,先破环为链,即 \(a_{n+i}=a_i, b_{n+i}=b_i\),此时就只需要跳到 \(x+n\) 而无需判环了。
如果顺时针走:
令 \(sum_i = \sum\limits_{j=1}^{i}{a_j-b_j}\),当能从 \(x\) 跳到 \(x+n\) 时,有
\[sum_{x-1} \le sum_x, sum_{x-1} \le sum_{x+1}, \dots, sum_{x-1} \le sum_{x+n-1} \]变形一下:
\[sum_{x-1} \le \min\limits_{x \le i < x+n}\{sum_i\} \]求长度不变区间的最小值,可以使用单调队列。
逆时针就反着再做一遍。
代码:
const int N = 1e6 + 5;
int n, hd, tl;
int a[N << 1], b[N << 1], c[N << 1], q[N << 1];
int ta[N], tb[N], ans[N], flag[N];
ll s[N << 1];
void solve() {
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + c[i];
for (int i = 1; i <= n; i++) s[i + n] = s[i + n - 1] + c[i];
for (int i = 1, hd = 1, tl = 0; i <= n * 2; i++) {
if (hd <= tl && q[hd] < i - n + 1) hd++;
while (hd <= tl && s[q[tl]] >= s[i]) tl--;
q[++tl] = i;
if (i >= n)
ans[i - n + 1] = s[q[hd]];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n;
for (int i = 1; i <= n; i++) {
std::cin >> a[i] >> b[i];
a[i + n] = a[i], b[i + n] = b[i];
c[i + n] = c[i] = a[i] - b[i];
}
solve();
for (int i = 1; i <= n; i++)
if (ans[i] >= s[i - 1])
flag[i] = 1;
for (int i = 1; i <= n; i++)
c[i] = a[n - i + 1] - b[((n - i ? n - i : n))];
solve();
for (int i = 1; i <= n; i++)
if (ans[i] >= s[i - 1])
flag[n - i + 1] = 1;
for (int i = 1; i <= n; i++)
std::cout << (flag[i] ? "TAK" : "NIE") << "\n";
return 0;
}
标签:std,le,POI2005,题解,sum,int,tl,Journey,P3422
From: https://www.cnblogs.com/Pengzt/p/17744050.html