定义一次操做为以\(1\)为根,选两个互相不为祖先的节点,交换它们的子树ios
定义一棵树的权值为至多进行一次操做的最大直径长度spa
初始只有节点\(1\),依次插入\(2\)~\(n\)号节点(做为已经存在的某个点的儿子),问每次插入后树的权值rest
强制在线code
\(1 \le n \le 2e5\),保证任意时刻树的形态合法string
容易发现使直径最大的操做方式是把与直径不想交的最长连接在直径的一端io
其实不用在乎祖先关系的限制,由于若是不合法你总能够选具备祖先关系两个点当“直径”的端点,另一个点所在的链砍下来接过去class
而后权值就转化成树上选\(3\)个点,两两距离之和\(/2 - 1\)再和直径取个\(\max\),直径端点又必定在这\(3\)个点中test
而后每次新加点就能够枚举它替换了原答案中的哪一个点,和原答案选个最优的更新stream
又因为每次插入的节点必定是叶子,能够简单地维护深度和倍增\(LCA\)date
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #define MAXN 200005 typedef long long LL; char gc(); int read(); int LCA(int, int); int dist(int, int); void update(int); int N, ans, anc[MAXN][20], dep[MAXN], p, q, r, dpq, dpr, dqr; int main() { freopen("forest.in", "r", stdin); freopen("forest.out", "w", stdout); read(), N = read(); p = q = r = 1; dpq = dpr = dqr = 0; for (int i = 2; i <= N; ++i) { anc[i][0] = read() ^ ans; dep[i] = dep[anc[i][0]] + 1; for (int j = 1; j < 20; ++j) { anc[i][j] = anc[anc[i][j - 1]][j - 1]; if (!anc[i][j]) break; } update(i); //local test //printf("%d\r\n", ans); printf("%d\n", ans); } return 0; } inline char gc() { static char buf[1000000], *p1, *p2; if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin); return p1 == p2 ? EOF : *p2++; } inline int read() { int res = 0; char ch = gc(); while (ch < '0' || ch > '9') ch = gc(); while (ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + ch - '0', ch = gc(); return res; } int LCA(int x, int y) { if (dep[x] < dep[y]) std::swap(x, y); for (int i = 19; i >= 0; --i) if (dep[anc[x][i]] >= dep[y]) x = anc[x][i]; if (x == y) return x; for (int i = 19; i >= 0; --i) if (anc[x][i] ^ anc[y][i]) x = anc[x][i], y = anc[y][i]; return anc[x][0]; } int dist(int x, int y) { int lca = LCA(x, y); return dep[x] + dep[y] - (dep[lca] << 1); } void update(int nx) { int dis1 = dist(nx, p), dis2 = dist(nx, q), dis3 = dist(nx, r); int ans1 = std::max(std::max(dpq, dis1), std::max(dis2, ((dpq + dis1 + dis2) >> 1) - 1)); int ans2 = std::max(std::max(dis1, dpr), std::max(dis3, ((dis1 + dpr + dis3) >> 1) - 1)); int ans3 = std::max(std::max(dis2, dis3), std::max(dqr, ((dis2 + dis3 + dqr) >> 1) - 1)); if (ans1 >= ans2 && ans1 >= ans3 && ans1 >= ans) { r = nx, dpr = dis1, dqr = dis2; ans = ans1; } else if (ans2 >= ans1 && ans2 >= ans3 && ans2 >= ans) { q = nx, dpq = dis1, dqr = dis3; ans = ans2; } else if (ans3 >= ans) { p = nx, dpq = dis2, dpr = dis3; ans = ans3; } } //Rhein_E 100pts