codeforces 570D.Tree Requests
[题目大意]:
给定一棵树,树的每个节点对应一个小写字母字符,有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=503000,inf=1000000000; int read(){ int x=0;bool flag=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')flag=1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} return flag?-x:x; } struct node{ int y,next; }e[maxn<<1]; int n,m; int linkk[maxn],len=0,sum[maxn]; int dfs_clock=0,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+1; dfs(e[i].y); } a[x].lat=++dfs_clock; } void init(){ n=read(),m=read();int x; up(i,2,n){ x=read(); insert(i,x); insert(x,i); fa[i]=x; } scanf("%s",s+1); a[1].dep=1; dfs(1); sort(a+1,a+n+1); for(int i=1;i<=n;i++)f[a[i].id]=i; } int find(int x,int Dep){ int left=1,right=n,mid; int L=0,R=0; while(left<=right){ mid=(left+right)>>1; if(a[mid].dep<Dep)left=mid+1; else { right=mid-1; if(a[mid].dep==Dep)L=mid; } } left=1,right=n,mid=0; while(left<=right){ mid=(left+right)>>1; if(a[mid].dep<=Dep){ left=mid+1; if(a[mid].dep==Dep)R=mid; } else right=mid-1; } if(!L&&!R)return 1; left=L,right=R; int u=0,v=0; while(left<=right){ mid=(left+right)>>1; if(a[mid].pre>=a[f[x]].pre){ right=mid-1; if(a[mid].pre>=a[f[x]].pre&&a[mid].pre<=a[f[x]].lat)u=mid; } else left=mid+1; } left=L,right=R; while(left<=right){ mid=(left+right)>>1; if(a[mid].pre<=a[f[x]].lat){ left=mid+1; if(a[mid].pre>=a[f[x]].pre&&a[mid].pre<=a[f[x]].lat)v=mid; } else right=mid-1; } if(!u||!v)return 1; int p=sum[v]^sum[u-1]; int cnt=0; while(p){ if(p&1)cnt++; p>>=1; } if(cnt>=2)return 0; else return 1; } void work(){ int x,y; for(int i=1;i<=n;i++)sum[i]=sum[i-1]^(1<<(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 0; }