您的位置:首页 > 其它

BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

2016-01-24 22:22 429 查看


求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N))

-----------------------------------------------------------------------------------

#include<cstdio>#include<cstring>#include<algorithm> using namespace std; typedef long long ll; const ll INF = -1LL << 60;const int maxn = 300009; char S[maxn];int w[maxn], N;int cnt[maxn], Sa[maxn], Rank[maxn], Height[maxn];int mx[maxn], mn[maxn], fa[maxn], sz[maxn], r[maxn];ll ans[maxn], tot[maxn]; void Init() { scanf("%d%s", &N, S); for(int i = 0; i < N; i++) scanf("%d", w + i); S[N++] = '$';} void Build() { int m = 255, *x = Height, *y = Rank; for(int i = 0; i < m; i++) cnt[i] = 0; for(int i = 0; i < N; i++) cnt[x[i] = S[i]]++; for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; for(int i = N; i--; ) Sa[--cnt[x[i]]] = i; for(int k = 1, p = 0; k <= N; k <<= 1, p = 0) { for(int i = N - k; i < N; i++) y[p++] = i; for(int i = 0; i < N; i++) if(Sa[i] >= k) y[p++] = Sa[i] - k; for(int i = 0; i < m; i++) cnt[i] = 0; for(int i = 0; i < N; i++) cnt[x[y[i]]]++; for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; for(int i = N; i--; ) Sa[--cnt[x[y[i]]]] = y[i]; swap(x, y), x[Sa[0]] = 0, p = 1; for(int i = 1; i < N; i++) { if(y[Sa[i]] != y[Sa[i - 1]] || y[Sa[i] + k] != y[Sa[i - 1] + k]) p++; x[Sa[i]] = p - 1; } if((m = p) >= N) break; } for(int i = 0; i < N; i++) Rank[Sa[i]] = i; Height[0] = 0; for(int i = 0, h = 0; i < N; i++) if(Rank[i]) { if(h) h--; while(S[i + h] == S[Sa[Rank[i] - 1] + h]) h++; Height[Rank[i]] = h; }} int Find(int x) { return x == fa[x] ? x : fa[x] = Find(fa[x]);} bool Cmp(const int &l, const int &r) { return Height[l] > Height[r];} inline void Max(ll &x, ll t) { if(t > x) x = t;}inline void Max(int &x, int t) { if(t > x) x = t;}inline void Min(int &x, int t) { if(t < x) x = t;} void Work() { for(int i = 0; i < N; i++) { sz[i] = 1; r[i] = fa[i] = i; mx[i] = mn[i] = w[i]; tot[i] = 0; ans[i] = INF; } sort(r, r + N, Cmp); for(int i = 0; i < N; i++) if(r[i] > 1) { int u = Find(Sa[r[i]]), v = Find(Sa[r[i] - 1]); if(u == v) continue; tot[Height[r[i]]] += ll(sz[u]) * sz[v]; Max(ans[Height[r[i]]], max(ll(mx[u]) * mx[v], ll(mn[u]) * mn[v])); fa[u] = v, sz[v] += sz[u]; Max(mx[v], mx[u]); Min(mn[v], mn[u]); } for(int i = Height[r[0]]; i--; ) tot[i] += tot[i + 1], Max(ans[i], ans[i + 1]); for(int i = 0; i + 1 < N; i++) printf("%lld %lld\n", tot[i], ans[i] != INF ? ans[i] : 0);} int main() { Init(); Build(); Work(); return 0;}-----------------------------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: