CF627F Island Puzzle 题解
题意
- 给定一棵 个点的树,每个点上都有一个 的数,任意两点上的数都不同。
- 每次你可以交换 所在的点和与其相连的任一点上的数,同时你可以最多加入一条边。
- 给定目标状态,你需要在加入的边数尽量小的前提下,求出最少的步数,或者判断无法达成目标。
- 。
题解
设初始时 在 ,目标时在 。
注意到操作的本质是 的移动,同时操作具有可逆性。
因此,我们先不考虑次数最少的要求,先让 从 以最短距离移动到 。
如果此时已经满足目标状态了,说明不需要加入新的边,此时 经过的距离即为最少步数。
否则,接下来我们只能加入一条新的边,然后让 从 出发,走到包含这条新边的环上距离 最近的点 ,绕若干次完整的圈之后,回到 。
观察这样操作对权值的变化可以得出, 到 的路径上的所有点的权值都不会改变,同时每绕圈一次,环上除了 之外的点上的权值变化形成一个循环,而绕若干圈则为一个轮换。
因此,权值要改变的点加上 应该在树上形成一条路径。
由此我们能够确定连边 ,可以 为根,找到所有权值需要改变的点, 即为这些点中深度最小的点的父节点,而路径 则由 和这些点构成。
如果深度最小的点的父节点不唯一,或者 和这些点无法构成一条路径,或者这些点的权值不是目标权值的一个轮换,则说明无解。
最后来考虑最小化操作次数。
对于一条加边 ,绕圈的方向有两种 和 ,分别计算取 即可。
假设从 ,由这个轮换对循环的次数 可以得到最小次数为 。
但注意这个最小次数是在先将 从 移到 的前提下,因此如果有重复的路径需要减掉。
总时间复杂度 ,由于复杂度是线性的所以常数什么的就不管了。
代码
#define Fail print(-1), exit(0);
const int N = 2e5 + 7;
int n, a[N], b[N], s, t, p, v[N], d[N];
vi e[N], g, h, A, B;
pi o = mp(N, 0);
bool dfs1(int x, int f) {
g.pb(x);
if (x == t) return 1;
for (auto y : e[x])
if (y != f && dfs1(y, x)) return 1;
g.pop_back();
return 0;
}
void dfs2(int x, int f, int d) {
if (a[x] != b[x]) {
h.pb(x), v[x] = 1;
if (d - 1 == o.fi && f != o.se) Fail;
if (d - 1 < o.fi) o = mp(d - 1, f);
}
for (auto y : e[x])
if (y != f) dfs2(y, x, d + 1);
}
void dfs3(int x, int f) {
if (x != p) A.pb(a[x]), B.pb(b[x]);
for (auto y : e[x])
if (y != f && v[y]) dfs3(y, x);
}
int dfs4(int x, int f, int d, int t) {
if (x == t) return d;
for (auto y : e[x])
if (y != f) {
int o = dfs4(y, x, d + 1, t);
if (o) return o;
}
return 0;
}
inline int calc(vi A, vi B) {
int pos = 0, siz = A.size();
for (ui i = 0; i < B.size(); i++)
if (B[i] == A[0]) pos = i;
if (!pos) return 0;
for (ui i = 0; i < A.size(); i++)
if (A[i] != B[(i+pos)%siz]) return 0;
return pos;
}
inline int S(int x, int y) {
return dfs4(x, 0, 0, y);
}
inline ll get(int x, int y) {
int c = calc(A, B);
return S(s, x) + 1ll * (c - 1) * (A.size() + 1) + 1 + S(y, t);
}
int main() {
rd(n);
for (int i = 1; i <= n; i++) rd(a[i]), s = a[i] ? s : i;
for (int i = 1; i <= n; i++) rd(b[i]), t = b[i] ? t : i;
for (int i = 1, x, y; i < n; i++)
rd(x), rd(y), e[x].pb(y), e[y].pb(x);
dfs1(s, 0);
for (ui i = 1; i < g.size(); i++) swap(a[g[i-1]], a[g[i]]);
bool ok = 1;
for (int i = 1; i <= n; i++) ok &= a[i] == b[i];
if (ok) return print(0, ' '), print(g.size() - 1), 0;
dfs2(t, 0, 0), h.pb(p = o.se), v[p] = 1;
for (auto x : h)
for (auto y : e[x])
if (v[y]) ++d[x];
vi u;
for (auto x : h)
if (d[x] == 1) u.pb(x);
else if (d[x] != 2) Fail;
if (u.size() != 2u) Fail;
if (u[0] > u[1]) swap(u[0], u[1]);
dfs3(u[0], 0);
if (!calc(A, B)) Fail;
print(u[0], ' '), print(u[1], ' ');
ll ans = get(u[0], u[1]);
reverse(A.begin(), A.end());
reverse(B.begin(), B.end());
print(min(ans, get(u[1], u[0])));
return 0;
}
评论
暂无已公开评论。