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

时间: 2024-09-30 01:35:29

codeforces 570D.Tree Requests的相关文章

Codeforces 570D TREE REQUESTS dfs序+树状数组 异或

http://codeforces.com/problemset/problem/570/D Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of?n?vertices. Each vertex contains a lowercase

Codeforces 570D Tree Requests(Dsu On the Tree)

题目链接 Tree Requests 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 7 typedef long long LL; 8 9 const int N = 500010; 10 const int A = 31; 11 12 int cntf[N], sz[N], h[N]; 13 vector <i

Codeforces 570D TREE REQUESTS dfs序+树状数组

链接 题解链接:点击打开链接 题意: 给定n个点的树,m个询问 下面n-1个数给出每个点的父节点,1是root 每个点有一个字母 下面n个小写字母给出每个点的字母. 下面m行给出询问: 询问形如 (u, deep) 问u点的子树中,距离根的深度为deep的所有点的字母能否在任意排列后组成回文串,能输出Yes. 思路:dfs序,给点重新标号,dfs进入u点的时间戳记为l[u], 离开的时间戳记为r[u], 这样对于某个点u,他的子树节点对应区间都在区间 [l[u], r[u]]内. 把距离根深度相

【思维题】 Codeforces 570D Tree Requests

通道 题意:一棵树,每个节点有一个点值(字符),问u子树的深度为k的所有节点组成的字符串是否为回文 思路:搜出dfs序及该节点的深度,那么u节点深度为K的那一段肯定在dfs序[l,r]区间内,然后对于回文的处理,要么这段异或和为0,要么lowbit(x)=x 代码: #include <bits/stdc++.h> using namespace std; const int maxn = 500005; typedef pair <int, int> PII; vector &l

codeforces 570 D. Tree Requests 树状数组+dfs搜索序

链接:http://codeforces.com/problemset/problem/570/D D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a low

Codeforces Round #316 (Div. 2) D. Tree Requests 树 离线在线 算法

D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a lowercase English letter. Vertex 1 is the root of the

codeforces 570 D. Tree Requests (dfs)

题目链接: 570 D. Tree Requests 题目描述: 给出一棵树,有n个节点,1号节点为根节点深度为1.每个节点都有一个字母代替,问以结点x为根的子树中高度为h的后代是否能够经过从新排序变成一个回文串? 解题思路: 判断是不是回文串,可以统计集合中出现过的字母的个数,出现奇数次的字母个数小于1,即为回文串,否则不是.所以我们可以使用状压统计当前区间中字母出现的奇偶次数. 对于如何快速的求出区间,先dfs整棵树,标记下来每个节点进栈的时间和出栈的时间,然后把高度一样的点按照进栈时间顺序

CF 570 D. Tree Requests

D. Tree Requests http://codeforces.com/problemset/problem/570/D 题意: 一个以1为根的树,每个点上有一个字母(a-z),每次询问一个子树内深度为h的点是否可以构成回文串.(深度是到1的深度,没有也算,空回文串) 分析: dsu on tree.询问子树信息. 判断是否构成回文:出现奇数次的字符小于等于1个. 代码: 1 #include<cstdio> 2 #include<algorithm> 3 #include&

CodeForces 570D DFS序 树状数组 Tree Requests

参考九野巨巨的博客. 查询一个子树内的信息,可以通过DFS序转成线形的,从而用数据结构来维护. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <map> 6 #define MP make_pair 7 #define FI first 8 #define SE second 9 using name