题目

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):无额外限制。

思路

注意到如果存在长度为nnn的回文串,则一定也存在长度为n−2n-2n−2的回文串。因此我们可以对串长分奇偶进行二分,然后检查是否存在给定长度的回文串。

首先考虑如何求经过给定点是否存在某个长度的回文串。回文串一定被这个点分成了两半。我们枚举长的这一半在哪个子树里,然后枚举这个子树中符合要求的点。这个点需要满足两个要求:

  1. 这个回文串上面的一段是回文串。
  2. 这个回文串下面的一段在从根到某个其它子树的路径上出现了。

代码

#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;
}

【noi.ac #1997】A. 制胡窜相关推荐

  1. 【LOJ】#2479. 「九省联考 2018」制胡窜

    题解 老了,国赛之前敲一个后缀树上LCT和线段树都休闲的很 现在后缀树上线段树合并差点把我写死 主要思路就是后缀树+线段树合并+容斥,我相信熟练的OIer看到这已经会了 但就是不想写 但是由于我过于老 ...

  2. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  3. NOI.AC#2007-light【根号分治】

    正题 题目链接:http://noi.ac/problem/2007 题目大意 nnn个格子排成一排,每个格子有一个0/10/10/1和一个颜色.开始每个格子都是000,qqq次操作取反一个颜色的所有 ...

  4. NOI.AC#2139-选择【斜率优化dp,树状数组】

    正题 题目链接:http://noi.ac/problem/2139 题目大意 给出nnn个数字的序列aia_iai​.然后选出一个不降子序列最大化子序列的aia_iai​和减去没有任何一个数被选中的 ...

  5. NOI.AC#2144-子串【SAM,倍增】

    正题 题目链接:http://noi.ac/problem/2144 题目大意 给出一个字符串sss和一个序列aaa.将字符串sss的所有本质不同子串降序排序后,求有多少个区间[l,r][l,r][l ...

  6. NOI.AC#2266-Bacteria【根号分治,倍增】

    正题 题目链接:http://noi.ac/problem/2266 题目大意 给出nnn个点的一棵树,有一些边上有中转站(边长度为222,中间有一个中转站),否则就是边长为111. mmm次询问一个 ...

  7. 野鸡NOI.AC模拟赛【2019.10.26】

    前言 截止至2019.10.2614:222019.10.26\ \ \ \ 14:222019.10.26    14:22 成绩 正题 T1:NOI.AC−T1:NOI.AC-T1:NOI.AC− ...

  8. noi.ac 405 bzoj 4403 序列统计 题解

    博客观赏效果更佳 题意简述 noi.ac再次蒯题,实锤了- 请你求长度在 [ 1 , n ] [1,n] [1,n] 范围内,值域在 [ l , r ] [l,r] [l,r] 范围内的序列中,不下降 ...

  9. noi.ac #543 商店

    我们考虑可并堆维护,从深到浅贪心选取. 用priority_queue启发式合并的话,是60pts: #include<iostream> #include<cstdio> # ...

  10. noi.ac 邀请赛1 By cellur925

    A. array 考场:上来就想暴力,首先第一个子任务肯定没问题,怎么搞都行.然后第二个子任务用个数组记下新修的值就行了.第三个子任务用一下等差数列求和公式帮助求解,每次都重新算(因为每次改变全部元素 ...

最新文章

  1. ecs安装tomcat和mysql_centos(Linux)系统阿里云ECS搭建 jdk,tomcat和MySQL环境,并部署web程序...
  2. JAVA中使用FTPClient实现文件上传下载
  3. 联盟和部落大战一触即发,你有票了吗?
  4. 第二十六讲:基础一开放封闭原则
  5. LiveVideoStackCon2019北京参会手册
  6. LeetCode OJ 147. Insertion Sort List
  7. 抗击肺炎,中国互联网公司在行动
  8. 3星难度-算式填符号
  9. 冯诺依曼结构和哈佛结构01
  10. 【译】JavaScript面试问题:事件委托和this
  11. text展示html,textview完美展示html格式代码
  12. win7与internet时间同步出错_【时间同步出错】win7系统同步internet时间总是提示同步时出错的解决方法...
  13. 数据敏捷,HTAP数据库既决效率又决生死
  14. Java剑开天门(二)
  15. java poi 读取word_Java poi读取word文档(本篇只能读取text内容)
  16. 精准DNA甲基化/羟甲基化测序(oxBS-seq)|易基因技术推介
  17. Docker 从入门到实践系列一 - 什么是Docker
  18. 做Web自动化前,你必会的几个技能
  19. 用java做小学数学系统_基于jsp的小学数学试卷生成-JavaEE实现小学数学试卷生成 - java项目源码...
  20. 卡尔曼滤波五个公式推导

热门文章

  1. 知识点滴 - 关于苹果认证MFI
  2. 双机热备的概念双机热备的概念
  3. 网页游戏的项目设计方案分享
  4. java计算税后工资switch语句_switch语句 计算个人所得税和税后收入 | 学步园
  5. 万恶的LayoutSubviews
  6. [2017湖南集训7-8]暗牧 虚树+最短路
  7. hardhat 教程及 hardhat-deploy 插件使用
  8. Windows下USB驱动开发入门小结
  9. 大神之路:Java再撸一遍:Java多特么的线程
  10. c语言手写平衡二叉树(一)