1. 程式人生 > >LOJ6066:「2017 山東一輪集訓 Day3」第二題

LOJ6066:「2017 山東一輪集訓 Day3」第二題

傳送門
二分答案 \(k\),考慮如何 \(hash\) 使得做起來方便
把每個點掛在 \(k+1\) 級祖先上,考慮在祖先上刪除
這道題巧妙在於其可以對於 \(dfs\) 序/括號序列 \(hash\)
這樣在 \(k+1\) 級祖先上暴力刪除就好了

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int maxn(2e5 + 5);
const ull base(19260817);

unordered_map <ull, int> hash_table;
int first[maxn], cnt, n, idx, dfn[maxn], ed[maxn], mxd[maxn], st[maxn], top;
ull val[maxn], pw[maxn], hsh[maxn];
vector <int> son[maxn], kson[maxn];

inline void Dfs1(int u) {
    dfn[u] = ++idx, val[idx] = 233;
    for (auto v : son[u]) Dfs1(v), mxd[u] = max(mxd[u], mxd[v]);
    ed[u] = ++idx, ++mxd[u], val[idx] = 131;
}

inline void Dfs2(int u, int k) {
    st[++top] = u;
    if (top - 1 > k) kson[st[top - k - 1]].push_back(u);
    for (auto v : son[u]) Dfs2(v, k);
    --top;
}

inline ull Hash(int l, int r) {
    return hsh[r] - hsh[l - 1] * pw[r - l + 1];
}

inline int Calc(int k) {
    register int i, l, r;
    register ull v;
    hash_table.clear();
    for (i = 1; i <= n; ++i) kson[i].clear();
    Dfs2(1, k);
    for (i = 1; i <= n; ++i)
        if (mxd[i] > k) {
            l = dfn[i], v = 0;
            for (auto to : kson[i]) {
                r = dfn[to] - 1;
                v = v * pw[r - l + 1] + Hash(l, r);
                l = ed[to] + 1;
            }
            r = ed[i], v = v * pw[r - l + 1] + Hash(l, r);
            if (hash_table.count(v)) return 1;
            hash_table[v] = 1;
        }
    return 0;
}

int main() {
    register int i, v, x, l, r, mid, ans;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i)
        for (scanf("%d", &x); x; --x) scanf("%d", &v), son[i].push_back(v);
    Dfs1(1), pw[0] = 1;
    for (i = 1; i <= idx; ++i) pw[i] = pw[i - 1] * base;
    for (i = 1; i <= idx; ++i) hsh[i] = hsh[i - 1] * base + val[i];
    l = 2, r = n, ans = 1;
    while (l <= r) Calc(mid = (l + r) >> 1) ? ans = mid, l = mid + 1 : r = mid - 1;
    printf("%d\n", ans);
    return 0;
}