day26T3改錯記

題目描述

定義一次操做爲以\(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
相關文章
相關標籤/搜索