제출 #1167315

#제출 시각아이디문제언어결과실행 시간메모리
1167315turnejaLampice (COCI19_lampice)C++20
17 / 110
3453 ms20352 KiB
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>

using namespace std;
using namespace __gnu_pbds;

#define endl "\n"
#define ll long long
#define IOS ios_base::sync_with_stdio(false); cin.tie(nullptr);

const int N = 1e5 + 5;
const int K = 19;

const long long M = 1e9 + 7;
const long long P = 26, INV_P = 576923081;
const long long Q = 53, INV_Q = 56603774;

struct chash {
    long long operator()(pair<long long, long long> x) const { return x.first* M + x.second; }
};

pair<long long, long long> single(char a) {
    return make_pair(a - 'a' + 1, a - 'a' + 1);
}

pair<long long, long long> mul(pair<long long, long long> a, pair<long long, long long> b) {
    return make_pair(a.first * b.first % M, a.second * b.second % M);
}

pair<long long, long long> sub(pair<long long, long long> a, pair<long long, long long> b) {
    return make_pair((a.first - b.first + M) % M, (a.second - b.second + M) % M);
}

pair<long long, long long> add(pair<long long, long long> a, pair<long long, long long> b) {
    return make_pair((a.first + b.first + M) % M, (a.second + b.second + M) % M);
}

string s;
int sz[N];
bool seen_c[N];
int parent_c[N];
int depth[N];
int color[N];
int up[K][N];

long long pw_p[N], pw_q[N];
long long inv_p[N], inv_q[N];
vector<int> adj[N];
pair<long long, long long> rising[N], falling[N];

gp_hash_table<pair<long long, long long>, int, chash> mp;
int ans = 1;
bool found = false;

int kth(int v, int k) {
    while (k > 0) {
        int l = log2(k);
        v = up[l][v];
        k ^= 1 << l;
    }
    return v;
}

void dfs_subtree(int u, int p) {
    sz[u] = 1;
    for (int v : adj[u]) {
        if (v != p && !seen_c[v]) {
            dfs_subtree(v, u);
            sz[u] += sz[v];
        }
    }
    return;
}

int dfs_centroid(int u, int p, int n) {
    for (int v : adj[u]) {
        if (v != p && !seen_c[v] && sz[v] > n / 2) {
            return dfs_centroid(v, u, n);
        }
    }
    return u;
}

void dfs1(int u, int p) {
    up[0][u] = p;
    for (int i = 1; i < K; i++) {
        up[i][u] = up[i - 1][up[i - 1][u]];
    }
    rising[u] = add(rising[p], mul(single(s[u]), make_pair(pw_p[depth[u]], pw_q[depth[u]])));
    falling[u] = add(mul(falling[p], make_pair(P, Q)), single(s[u]));
    for (int v : adj[u]) {
        if (v != p && !seen_c[v]) {
            depth[v] = depth[u] + 1;
            dfs1(v, u);
        }
    }
    return;
}

void dfs2(int u, int p, int k) {
    if (depth[u] + 1 == k) {
        if (rising[u] == falling[u]) {
            found = true;
        }
    } else if (depth[u] + 1 < k) {
        int anc = k - (depth[u] + 1);
        if (anc <= depth[u]) {
            anc = kth(u, anc);
            if (rising[anc] == falling[anc]) {
                pair<long long, long long> h = mul(sub(rising[u], rising[anc]), make_pair(inv_p[depth[anc] + 1], inv_q[depth[anc] + 1]));
                auto it = mp.find(h);
                if (it != mp.end()) {
                    found = true;
                }
            }
        }
    }
    for (int v : adj[u]) {
        if (v != p && !seen_c[v]) {
            dfs2(v, u, k);
        }
    }
    return;
}

void dfs3(int u, int p, int c) {
    mp[mul(sub(rising[u], rising[c]), make_pair(INV_P, INV_Q))] = 1;
    for (int v : adj[u]) {
        if (v != p && !seen_c[v]) {
            dfs3(v, u, c);
        }
    }
    return;
}


void build(int u, int p, int n) {
    dfs_subtree(u, u);
    int c = dfs_centroid(u, u, sz[u]);
    if (p == -1) {
        p = c;
    }
    parent_c[c] = p;
    seen_c[c] = true;

    rising[c] = make_pair(s[c] - 'a' + 1, s[c] - 'a' + 1);
    falling[c] = rising[c];
    up[0][c] = c;
    for (int i = 1; i < K; i++) {
        up[i][c] = c;
    }
    depth[c] = 0;
    for (int v : adj[c]) {
        if (!seen_c[v]) {
            depth[v] = 1;
            dfs1(v, c);
        }
    }

    int l = 0, r = n;
    while (l <= r) {
        found = false;
        int mid = (l + r) / 2;
        for (int v : adj[c]) {
            if (!seen_c[v]) {
                dfs2(v, c, 2 * mid + 1);
                dfs3(v, c, c);
            }
        }
        mp.clear();
        reverse(adj[c].begin(), adj[c].end());
        for (int v : adj[c]) {
            if (!seen_c[v]) {
                dfs2(v, c, 2 * mid + 1);
                dfs3(v, c, c);
            }
        }
        mp.clear();
        reverse(adj[c].begin(), adj[c].end());
        if (found) {
            ans = max(ans, 2 * mid + 1);
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }

    l = 1, r = n;
    while (l <= r) {
        found = false;
        int mid = (l + r) / 2;
        for (int v : adj[c]) {
            if (!seen_c[v]) {
                dfs2(v, c, 2 * mid);
                dfs3(v, c, c);
            }
        }
        mp.clear();
        reverse(adj[c].begin(), adj[c].end());
        for (int v : adj[c]) {
            if (!seen_c[v]) {
                dfs2(v, c, 2 * mid);
                dfs3(v, c, c);
            }
        }
        mp.clear();
        reverse(adj[c].begin(), adj[c].end());
        if (found) {
            ans = max(ans, 2 * mid);
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }

    for (int v : adj[c]) {
        if (!seen_c[v]) {
            build(v, c, n);
        }
    }
    return;
}


int main() {
    IOS;
    int n;
    cin >> n >> s;
    pw_p[0] = 1, pw_q[0] = 1;
    inv_p[0] = 1, inv_q[0] = 1;
    for (int i = 1; i < n; i++) {
        pw_p[i] = pw_p[i - 1] * P % M;
        pw_q[i] = pw_q[i - 1] * Q % M;
        inv_p[i] = inv_p[i - 1] * INV_P % M;
        inv_q[i] = inv_q[i - 1] * INV_Q % M;
    }

    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    build(0, -1, n);
    cout << ans;

    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...