제출 #655590

#제출 시각아이디문제언어결과실행 시간메모리
655590bebraLampice (COCI19_lampice)C++17
110 / 110
4555 ms16140 KiB
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("fast-math")
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct pair_hash {
    template<typename T1, typename T2>
    std::size_t operator() (const std::pair<T1, T2>& pair) const {
        return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
    }
};

using my_set = unordered_set<pair<ll, int>, pair_hash>;

#define dbg(x) cerr << #x << ": " << x << endl;

// need to build first then search

const ll MOD = 1223376683;
const ll BASE = 449653;
// const ll BASE = 10;
const int MAX_N = 50000 + 5;
const int MAX_LOG = 17;

vector<int> g[MAX_N];

ll a[MAX_N];
ll powers[MAX_N];

ll hash_forward[MAX_N];
ll hash_reverse[MAX_N];

ll hash2_forward[MAX_N];
ll hash2_reverse[MAX_N];

ll curr_value[MAX_N];
ll curr_value2[MAX_N];

int sz[MAX_N];
bool used[MAX_N];
int dist[MAX_N];

bool found;
int curr_len;

inline void dfs_calc(int v, int p) {
    sz[v] = 1;
    for (int u : g[v]) {
        if (used[u] || u == p) continue;
        dfs_calc(u, v);
        sz[v] += sz[u];
    }
}

inline int find_centroid(int v, int p, int n) {
    for (int u : g[v]) {
        if (used[u] || u == p) continue;
        if (2 * sz[u] > n) {
            return find_centroid(u, v, n);
        }
    }
    return v;
}

inline void dfs_traverse(int v, int p, const my_set& curr_hashes) {
    dist[v] = dist[p] + 1;
    hash_forward[v] = (hash_forward[p] * BASE + a[v]) % MOD;
    hash_reverse[v] = (hash_reverse[p] + powers[dist[v]] * a[v]) % MOD;

    if (dist[p] == 0) {
        hash2_forward[v] = a[v];
        hash2_reverse[v] = a[v];
    } else {
        hash2_forward[v] = (hash2_forward[p] * BASE + a[v]) % MOD;
        hash2_reverse[v] = (hash2_reverse[p] + powers[dist[v] - 1] * a[v]) % MOD;
    }

    if (curr_len - dist[v] >= 1) {
        curr_value[v] = (hash_reverse[v] * powers[curr_len - dist[v] - 1] - hash_forward[v]) % MOD;
        if (curr_value[v] < 0) curr_value[v] += MOD;
    }
    if (curr_len - dist[v] >= 0) {
        ll curr = (hash2_reverse[v] * powers[curr_len - dist[v]] - hash2_forward[v]) % MOD;
        if (curr < 0) curr += MOD;

        if (curr_hashes.find(make_pair(curr, curr_len - dist[v] - 1)) != curr_hashes.end()) {
            found = true;
        }
    }

    if (hash_forward[v] == hash_reverse[v] && dist[v] + 1 == curr_len) {
        found = true;
    }

    if (dist[v] > curr_len) {
        return;
    }

    for (int u : g[v]) {
        if (used[u] || u == p) continue;
        dfs_traverse(u, v, curr_hashes);
    }
}

inline void dfs_apply(int v, int p, my_set& curr_hashes) {
    if (curr_len - dist[v] >= 0) {
        curr_hashes.insert(make_pair(curr_value[v], dist[v]));
    } else {
        return;
    }
    for (int u : g[v]) {
        if (used[u] || u == p) continue;
        dfs_apply(u, v, curr_hashes);
    }
}

inline void dfs_build(int v = 0) {
    dfs_calc(v, -1);
    int c = find_centroid(v, -1, sz[v]);
    used[c] = true;
    dist[c] = 0;
    hash_forward[c] = a[c];
    hash_reverse[c] = a[c];
    my_set curr_hashes;
    for (int u : g[c]) {
        if (!used[u]) {
            dfs_traverse(u, c, curr_hashes);
            dfs_apply(u, c, curr_hashes);
        }
    }
    for (int u : g[c]) {
        if (!used[u]) {
            dfs_build(u);
        }
    }
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    string s;
    cin >> s;
    for (int i = 0; i < n; ++i) {
        a[i] = (int)(s[i] - 'a') + 1;
    }
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    powers[0] = 1;
    for (int i = 1; i < MAX_N; ++i) {
        powers[i] = (powers[i - 1] * BASE) % MOD;
    }
    int ans = 1;
    // binsearch on radius of palindrome
    // odd case
    {
        int l = 0;
        int r = n / 2 + 1;
        while (l != r - 1) {
            int m = (l + r) / 2;
            curr_len = 2 * m + 1;
            found = false;
            memset(used, 0, sizeof(used));
            if (curr_len > n) {
                r = m;
                continue;
            }
            dfs_build();    
            if (found) {
                l = m;
            } else {
                r = m;
            }
        }
        ans = max(ans, 2 * l + 1);
    }
    // even case
    {
        int l = 0;
        int r = n / 2 + 1;
        while (l != r - 1) {
            int m = (l + r) / 2;
            curr_len = 2 * m;
            found = false;
            memset(used, 0, sizeof(used));
            if (curr_len > n) {
                r = m;
                continue;
            }
            dfs_build();    
            if (found) {
                l = m;
            } else {
                r = m;
            }
        }
        ans = max(ans, 2 * l);
    }
    cout << ans << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...