題目
Description
你有一顆nn個點的樹,樹的每一個節點上有一個小寫字母。你想知道,選擇樹上的一條簡單路徑(可以只包含一個點),使得經過的點上的字母構成的字符串是迴文串,這個迴文串的最大長度是多少?
Input format
第一行一個整數nn。
第二行一個長度爲nn的由小寫字母組成的字符串,其中第ii個字符表示ii號點上的字符。
接下來n−1n−1行每行兩個整數a,ba,b,代表樹上有一條邊(a,b)(a,b)。
Output format
一行一個整數,表示最長迴文串的長度。
Sample input 1
7
imanade
1 2
2 3
3 4
4 5
5 6
6 7
Sample output 1
3
Sample input 2
4
aabb
1 2
1 3
3 4
Sample output 2
2
Sample input 3
8
acdbabcd
1 6
6 7
6 3
3 4
4 5
5 2
8 5
Sample output 3
5
Constraints
保證1≤n≤500001≤n≤50000。保證SS只包含小寫字母。
本題採用子任務的方式評測。
子任務一(12pts12pts):n≤3000n≤3000。
子任務二(16pts16pts):保證ii號點和i+1i+1號點之間由一條邊(1≤i<n1≤i<n)。
子任務三(16pts16pts):保證樹上至多有100100個點的度爲11。
子任務四(56pts56pts):無額外限制。
思路
注意到如果存在長度爲的迴文串,則一定也存在長度爲的迴文串。因此我們可以對串長分奇偶進行二分,然後檢查是否存在給定長度的迴文串。
首先考慮如何求經過給定點是否存在某個長度的迴文串。迴文串一定被這個點分成了兩半。我們枚舉長的這一半在哪個子樹裏,然後枚舉這個子樹中符合要求的點。這個點需要滿足兩個要求:
- 這個迴文串上面的一段是迴文串。
- 這個迴文串下面的一段在從根到某個其它子樹的路徑上出現了。
代碼
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int N=50077,base=131;
int n,root,st;
int mx[N],vis[N],siz[N],dep[N],totsize,p[N];
ll pw[N],h[N],rh[N];
char s[N];
vector<int> G[N],g[N];
int ans=1;
void get_rt(int u,int f){
mx[u]=0,siz[u]=1;
for(int v:G[u]) {
if(vis[v]||v==f) continue;
get_rt(v,u);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u],totsize-siz[u]);
if(mx[root]>mx[u]) root=u;
}
void recalc_siz(int u,int f){
siz[u]=1;
for(int v:G[u]) {
if(vis[v]||v==f) continue;
recalc_siz(v,u);
siz[u]+=siz[v];
}
}
void dfs_get(int u){
recalc_siz(u,0);
vis[u]=1;
for(int v:G[u]){
if(vis[v]) continue;
totsize=siz[v],root=0;
get_rt(v,0);
g[u].push_back(root);
dfs_get(root);
}
}
gp_hash_table<ll,int> mp;
void get_hash(int u,int f){
dep[u]=dep[f]+1;
h[u]=h[f]*base+s[u]-'a'+1,rh[u]=(s[u]-'a'+1)*pw[dep[u]-1]+rh[f];
mp[h[u]]++;
for(int v:G[u]) {
if(vis[v]||v==f) continue;
get_hash(v,u);
}
}
void clear(int u,int f,int val){
mp[h[u]]+=val;
for(int v:G[u]){
if(vis[v]||v==f) continue;
clear(v,u,val);
}
}
bool get_ans(int u,int f,int l){
p[dep[u]]=u;
if(dep[u]>l) return 0;
if(dep[u]>=l/2+1){
int t=l-dep[u]+1;
if(mp[h[u]-h[p[dep[u]-t]]*pw[t]]>0) {
if(h[p[dep[u]-t+1]]==rh[p[dep[u]-t+1]]) {
return 1;
}
}
}
for(int v:G[u]){
if(v==f||vis[v]) continue;
if(get_ans(v,u,l)) return 1;
}
return 0;
}
bool dfs(int u,int l){
vis[u]=1;h[u]=dep[u]=0;mp.clear();
get_hash(u,0);p[1]=u;
for(int v:G[u]){
if(vis[v]) continue;
clear(v,u,-1);
if(get_ans(v,u,l)) return 1;
clear(v,u,1);
}
for(int v:g[u]) if(dfs(v,l)) return 1;
return 0;
}
inline bool chk(int x){
memset(vis,0,sizeof(vis));
return dfs(st,x);
}
int main(){
scanf("%d",&n);
scanf("%s",s+1);
pw[0]=1;
for(int i=1;i<=n;i++) pw[i]=pw[i-1]*base;
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
mx[0]=n;
root=0,totsize=n;get_rt(1,0);
st=root;
dfs_get(root);
int l=1,r=n/2;
while(l<=r){
int mid=(l+r)>>1;
if(chk(2*mid)) l=mid+1,ans=max(ans,2*mid);
else r=mid-1;
}
l=1,r=(n-1)/2;
while(l<=r){
int mid=(l+r)>>1;
if(chk(2*mid+1)) l=mid+1,ans=max(ans,2*mid+1);
else r=mid-1;
}
printf("%d",ans);
return 0;
}