【并查集 单调栈】最短路
题面

思路
先考虑求最短路。
如果一个点开始往前走了,那就不用往后走了,因为它一开始就可以往后走。
所以我们先处理往后走的,再处理往前走的。
往后:用一个单调栈维护单调递增的最短路(从前往后扫点,肯定是往后靠的且小的用来更新答案)
往前:在往后的步骤中预处理,用并查集标记更新过的点
每个点为起点进行操作,计算答案即可
代码
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
std::vector<int> h[6001];
struct node {
int dis, p;
}s[6001];
int n, tot, ans;
int a[6001], b[6001], f[6001], fa[6001];
int find(int x) {
return fa[x] = fa[x] != x ? find(fa[x]) : x;
}
int main() {
scanf("%d", &n);
for (int i = 2; i <= n; i++)
scanf("%d", &a[i]);
a[1] = 1;
for (int i = 2; i <= n; i++)
scanf("%d", &b[i]);
for (int i = 1; i <= n; i++) {
tot = 0;
memset(f, 127 / 3, sizeof(f));
for (int j = 0; j <= n; j++) h[j].clear();
f[i] = 0;
s[++tot] = (node){0, i};
h[0].push_back(i);
for (int j = i + 1; j <= n; j++) {
while (tot > 0 && s[tot].p >= b[j]) tot--;
tot++;
f[j] = s[tot].dis + 1;
s[++tot] = (node){f[j], j};
h[f[j]].push_back(j);
}
for (int j = 1; j <= n; j++)
fa[j] = j;
for (int ll = 0; ll <= n; ll++)
for (int j = 0; j < h[ll].size(); j++)
for (int xx = find(h[ll][j] - 1); xx >= a[h[ll][j]]; xx = find(xx - 1))//往后1个点跳
if (f[xx] > ll + 1) {
f[xx] = ll + 1;
fa[xx] = xx - 1;
h[f[xx]].push_back(xx);
} else fa[xx] = xx - 1;
for (int j = 1; j <= n; j++)
ans ^= f[j] * (i + j);
}
printf("%d", ans);
}

浙公网安备 33010602011771号