题意: 给你sa数组和manacher数组,构造字典序最小原串
由sa数组可以得到S[sa[i]] <= S[sa[i+1];当rank[sa[i]+1] > rank[sa[i+1]+1] 时, S[sa[i]] < S[sa[i+1],此时i+1向i连边。
由最长回文串可知S[L] == S[R], S[L-1] != S[R+1], 相等关系通过并查集合并,不相等关系决定了rank[L-1] rank[R+1]的大小关系,此时也连一条边
最后按sa[i]顺序贪心构造,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
using namespace std;
#define N (300010)
#define M (2000020)
#define LL long long
#define ULL unsigned long long
#define eps 1e-8
#define pii pair<int, int>
#define MP make_pair
#define ls (i<<1)
#define rs (i<<1|1)
#define md (ll+rr>>1)
#define lson ll, md, ls
#define rson md+1, rr, rs
#define DEBUG 0
int fst[N], vv[M], nxt[M], e;
int sa[N], Rank[N], fa[N], p[N];
char ans[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void init() {
memset(fst, -1, sizeof fst);
e = 0;
}
void add(int u, int v) {
vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
}
int main() {
int T;
int cas =1 ;
scanf("%d", &T);
while(T--) {
init();
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &sa[i]);
for(int i = 1; i < 2*n; ++i) scanf("%d", &p[i]), p[i]++;
fa[0] = 0;
sa[0] = n;
for(int i = 1; i <= n; ++i) {
Rank[sa[i]] = i;
fa[i] = i;
}
Rank[n] = 0;
for(int i = 1; i < n; ++i) {
if(Rank[sa[i] + 1] > Rank[sa[i+1]+1])
add(i+1, i);
}
p[0] = 1;
p[2*n] = 1;
int id = 0, mx = 1;
bool fail = 0;
for(int i = 1; i < 2*n && !fail; ++i) {
int cur;
if(i < mx) cur = min(p[id*2-i], mx - i);
else cur = 1;
if(p[i] < cur || i - p[i] + 1< 0 || i + p[i] - 1 > 2*n) fail = 1;
for(int ll = i-cur, rr = i+cur; rr < i+p[i] && !fail; --ll, ++rr) if(ll & 1){
int u = Rank[ll/2], v = Rank[rr/2];
if(u > v) swap( u, v);
for(u = find(u); u < v && !fail; --v) {
v = find(v);
if(u >= v) break;
for(int i = fst[v]; ~i; i = nxt[i]) {
if(vv[i] >= u) {
fail = 1;
break;
}
}
fa[v] = u;
}
}
if(((i-p[i]) & 1 ^ 1) && i - p[i] >= 0 && i + p[i] <= 2*n) fail = 1;
if(i-p[i] > 0 && i+p[i] < 2*n){
int u = Rank[(i-p[i])/2], v = Rank[(i+p[i])/2];
u = find(u); v = find(v);
if(u > v) swap(v, u);
add(v, u);
}
if(i+p[i] > mx)
mx = i + p[i], id = i;
}
char pre = 'a';
for(int i = 1; i <= n && !fail; ) {
int j = i;
char cur = pre;
for(;j <= n && find(j) == find(i); ++j);
for(int k = i; k < j; ++k) {
for(int t = fst[k]; ~t; t = nxt[t]){
int v = vv[t];
if(find(v) == find(i)) fail = 1;
else if(cur <= ans[sa[v]]) cur = ans[sa[v]] + 1;
}
}
if(cur > 'z') {
fail = 1;
break;
}
for(int k = i; k < j; ++k)
ans[sa[k]] = cur;
pre = cur;
i = j;
}
printf("Case #%d: ", cas++);
if(fail) {
puts("Wrong calculation!");
continue;
}
ans[n] = 0;
printf("%s\n", ans);
}
}