[题目大意]:

给定一棵树,树的每个节点对应一个小写字母字符,有m个询问,每次询问以vi为根节点的子树中,深度为hi的所有节点对应的字符能否组成一个回文串;

[题目分析]:

先画个图,可看出每次询问的所有节点都是一个从1开始bfs遍历完成的节点序列中的一段,已知深度hi的情况下,可以二分得到深度为hi的那一段的位置;

那么如何满足找到的节点必须在以vi为根的子树内这个条件?

可以想到dfs的时间戳,把1-n的数组按深度排序,深度相同的按照dfs时间戳排序;

这样就可以二分得到要求的所有节点的位置;

这样可以O(n)

分析回文串可知,如果奇数数量的字符不超过1个,那么一定能组成回文串;

用前缀和xor优化;

可以做到O(nlogn);

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iomanip>
#include<map>
#include<set>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
#define LL long long
#define up(i,j,n) for(int i=(j);(i)<=(n);(i)++)
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
#define FILE "1"
#define pii pair<int,int>
const int maxn=,inf=;
int read(){
int x=;bool flag=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')flag=;ch=getchar();}
while(ch<=''&&ch>=''){x=x*+ch-'';ch=getchar();}
return flag?-x:x;
}
struct node{
int y,next;
}e[maxn<<];
int n,m;
int linkk[maxn],len=,sum[maxn];
int dfs_clock=,fa[maxn];
char s[maxn];
int f[maxn];
struct Node{
int dep,pre,lat,id;
bool operator<(const Node &b)const{return dep<b.dep||(dep==b.dep&&pre<b.pre);}
}a[maxn];
void insert(int x,int y){
e[++len].y=y;
e[len].next=linkk[x];
linkk[x]=len;
}
void dfs(int x){
a[x].pre=++dfs_clock;a[x].id=x;
for(int i=linkk[x];i;i=e[i].next){
if(e[i].y==fa[x])continue;
a[e[i].y].dep=a[x].dep+;
dfs(e[i].y);
}
a[x].lat=++dfs_clock;
}
void init(){
n=read(),m=read();int x;
up(i,,n){
x=read();
insert(i,x);
insert(x,i);
fa[i]=x;
}
scanf("%s",s+);
a[].dep=;
dfs();
sort(a+,a+n+);
for(int i=;i<=n;i++)f[a[i].id]=i;
}
int find(int x,int Dep){
int left=,right=n,mid;
int L=,R=;
while(left<=right){
mid=(left+right)>>;
if(a[mid].dep<Dep)left=mid+;
else {
right=mid-;
if(a[mid].dep==Dep)L=mid;
}
}
left=,right=n,mid=;
while(left<=right){
mid=(left+right)>>;
if(a[mid].dep<=Dep){
left=mid+;
if(a[mid].dep==Dep)R=mid;
}
else right=mid-;
}
if(!L&&!R)return ;
left=L,right=R;
int u=,v=;
while(left<=right){
mid=(left+right)>>;
if(a[mid].pre>=a[f[x]].pre){
right=mid-;
if(a[mid].pre>=a[f[x]].pre&&a[mid].pre<=a[f[x]].lat)u=mid;
}
else left=mid+;
}
left=L,right=R;
while(left<=right){
mid=(left+right)>>;
if(a[mid].pre<=a[f[x]].lat){
left=mid+;
if(a[mid].pre>=a[f[x]].pre&&a[mid].pre<=a[f[x]].lat)v=mid;
}
else right=mid-;
}
if(!u||!v)return ;
int p=sum[v]^sum[u-];
int cnt=;
while(p){
if(p&)cnt++;
p>>=;
}
if(cnt>=)return ;
else return ;
}
void work(){
int x,y;
for(int i=;i<=n;i++)sum[i]=sum[i-]^(<<(s[a[i].id]-'a'));
while(m--){
x=read(),y=read();
if(find(x,y))printf("Yes\n");
else printf("No\n");
}
}
int main(){
init();
work();
return ;
}

最新文章

  1. Entity Framework 6 Recipes 2nd Edition(10-8)译 - &gt;映射插入、修改、删除操作到存储过程
  2. 【Android】Ignoring InnerClasses attribute for an anonymous inner class
  3. C#3.0 扩展方法
  4. 第三次作业——个人作业,k米案例分析
  5. GIS简单计算Helper类
  6. SharePoint 服务器端对象模型 之 使用LINQ进行数据访问操作(Part 2)
  7. 《极客学院 --NSAttributedString 使用详解-4-UITextKit 简介》学习笔记(待处理)
  8. Go语言的类型转化
  9. Shell遍历文件的每一行[转载]
  10. 操作引入xml文件的书包(定位到指定节点)
  11. Hibernate 一对一关联映射,mappedBy参数解析
  12. 轻量化卷积神经网络MobileNet论文详解(V1&amp;V2)
  13. 寒冬之下,移动开发没人要了? 浅谈 iOS 开发者该 何去何从?
  14. 实验吧MD5之守株待兔解题思路
  15. wpf UI 元素类型
  16. LODOP弹出对话框获取保存文件的路径
  17. LOJ115 无源汇有上下界可行流(上下界网络流)
  18. 脚本路径问题_dirname
  19. if语句格式及流程
  20. WinRT IO相关整理

热门文章

  1. Codeforces Gym101606 E.Education (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))
  2. tomcat7.0.55配置单向和双向HTTPS连接(二)
  3. robot upstart 问题
  4. android 扩大view的响应区域
  5. 搭建服务与负载均衡的客户端-Spring Cloud学习第二天(非原创)
  6. java -agent与Javassist
  7. 品质与合身 无须昂贵 | Tailorwoods在线男装定制
  8. 【IntelliJ idea/My/ecplise】启动项目前,修改配置JVM参数
  9. tensorflow提示出错&#39;module&#39; object has no attribute &#39;pack&#39;
  10. 偏执的iOS逆向研究员:收集全版本的macOS iOS+越狱+内核调试