Codeforces Round #316 (Div. 2) D

题意:给你一个一棵树,树上的每个节点上有一个字符,询问 v,deep, 问深度为deep的,并且属于v子树的所有字符能不能组成一个回文,是数Yes,否则No

对于这颗树,我们可以用 时间戳 来表示点v所包含的区间

然后对于每一层我们可以把这些字符存在一个数组里面

所以要找到 属于V的字符,且在deep层

我们可以对于这一层进行二分(因为在同义层的时间时递增的)

#include<bits/stdc++.h>
using namespace std;
const int mmax = 5e5+10;
int n,m;
int depp[mmax],TT;
char p[mmax];
struct Node{
    int num[26];
};
vector<char>sum[mmax];
vector<int>ID[mmax];
vector<Node>ans[mmax];
vector<int>tp[mmax];
bool vit[mmax];
struct node{
    int st,ed;
}pp[mmax];
void dfs(int x,int cnt){
    sum[cnt].push_back(p[x]);
    ID[cnt].push_back(x);
    TT++;vit[x]=1;
    pp[x].st=TT;
    for(int i=0;i<tp[x].size();i++){
        int to=tp[x][i];
        if(!vit[to]) dfs(to,cnt+1);
    }
    pp[x].ed=TT;
}
void init(){
    for(int i=0;i<=n;i++) {
        sum[i].clear();
        tp[i].clear();
        ID[i].clear();
        ans[i].clear();
    }
    memset(ans,0,sizeof(ans));
    memset(vit,0,sizeof(vit));
}
int lfind(int l,int r,int x,int b){
    int mid,ans=mmax;
    while(l<=r){
        mid=(l+r)>>1;
        int id=ID[b][mid];
        if(pp[id].st>=pp[x].st){
            ans=mid;r=mid-1;
        }
        else l=mid+1;
    }
    return ans;
}
int rfind(int l,int r,int x,int b){
    int mid,ans=-1;
    while(l<=r){
        mid=(l+r)>>1;
        int id=ID[b][mid];
        if(pp[id].ed<=pp[x].ed){
            ans=mid;l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
    #endif // ONLINE_JUDGE
    while(cin>>n>>m){
        init();
        for(int i=2;i<=n;i++){
            int a;scanf("%d",&a);
            tp[a].push_back(i);
            tp[i].push_back(a);
        }
        TT=0;
        scanf("%s",p+1);
        dfs(1,1);
        for(int i=1;i<=n;i++){
            if(sum[i].size()==0) continue;
             Node a;
            memset(a.num,0,sizeof(a.num));
            for(int j=0;j<sum[i].size();j++){
                int id=sum[i][j]-‘a‘;
                a.num[id]++;
                ans[i].push_back(a);
            }
        }
        for(int i=0;i<m;i++){
            int a,b;scanf("%d%d",&a,&b);
            int ll,rr;
            ll=lfind(0,ans[b].size()-1,a,b);
            rr=rfind(0,ans[b].size()-1,a,b);
            if(ll>rr) puts("Yes");
            else{
                int tsum=0;
                if(ll==0){
                    tsum=0;
                    for(int j=0;j<26;j++) if(ans[b][rr].num[j]&1) tsum++;
                }
                else{
                    Node a;
                    for(int j=0;j<26;j++)
                    a.num[j]=ans[b][rr].num[j]-ans[b][ll-1].num[j];
                    tsum=0;
                    for(int j=0;j<26;j++) if(a.num[j]&1) tsum++;

                }
                if(tsum>1) puts("No");
                else puts("Yes");
            }
        }
    }
}
时间: 2024-10-25 11:45:52

Codeforces Round #316 (Div. 2) D的相关文章

Codeforces Round #316 (Div. 2) B. Simple Game

思路:把n分成[1,n/2],[n/2+1,n],假设m在左区间.a=m+1,假设m在右区间,a=m-1.可是我居然忘了处理1,1这个特殊数据.被人hack了. 总结:下次一定要注意了,提交前一定要看下边界数据,不要急着交. 题目链接:http://codeforces.com/problemset/problem/570/B <pre name="code" class="cpp">#include<bits/stdc++.h> using

Codeforces Round #316 (Div. 2) C. Replacement

题意:给定一个字符串,里面有各种小写字母和' . ' ,无论是什么字母,都是一样的,假设遇到' . . ' ,就要合并成一个' .',有m个询问,每次都在字符串某个位置上将原来的字符改成题目给的字符,问每次须要多少次合并次数.才使字符串没有' .. ' 思路:最原始的想法,就是对于每一次询问,都遍历整个字符串.这样时间复杂度o(n*m),就高达10^10方,非常明显会tle. 换下思路,事实上每次询问所改变的字符都会保留到下一次.也就是下一次的次数就会受到上一次的影响,那么我仅仅要就算出第一次的

Codeforces Round #316 (Div. 2) D计算在一棵子树内某高度的节点

题:https://codeforces.com/contest/570/problem/D 题意:给定一个以11为根的n个节点的树,每个点上有一个字母(a~z),每个点的深度定义为该节点到11号节点路径上的点数.每次询问a,ba,b查询以aa为根的子树内深度为bb的节点上的字母重新排列之后是否能构成回文串.分析:很明显是个树上启发式合并.显然,只要深度为bb结点的所有颜色中,至多有一种的数量为奇数就可以构成回文串了. #include<bits/stdc++.h> using namespa

Codeforces Round #316 (Div. 2) A

Description The country of Byalechinsk is running elections involving n candidates. The country consists of m cities. We know how many people in each city voted for each candidate. The electoral system in the country is pretty unusual. At the first s

Codeforces Round #316 (Div. 2) D Tree Requests

官方题解是离线询问,dfs树形转线性,然后二分找区间. 还有一种比较好的做法是直接dfs,将当前访问这个结点u相关的询问之前的状态存起来,然后访问完以后利用异或开关性,得到这颗子树上的答案. 代码是学习别人的http://blog.csdn.net/squee_spoon/article/details/47666667 当时做的时候想得是树形转线性,觉得dfs会暴栈,想用bfs,之前又没写过,于是愣了一个钟头. #include<bits/stdc++.h> using namespace

2017-4-30-Train:Codeforces Round #316 (Div. 2)

A. Elections(模拟) The country of Byalechinsk is running elections involving n candidates. The country consists of m cities. We know how many people in each city voted for each candidate. The electoral system in the country is pretty unusual. At the fi

Codeforces Round #316 (Div. 2)E. Pig and Palindromes DP

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

Codeforces Round #316 (Div. 2)C. Replacement(模拟)

传送门 Description Daniel has a string s, consisting of lowercase English letters and period signs (characters '.'). Let's define the operation of replacement as the following sequence of steps: find a substring ".." (two consecutive periods) in st

570D Codeforces Round #316 (Div. 2) D(dfs序,时间戳,二分

题目:一棵树上每个节点有个字符值,询问每个节点的深度为h的子节点的字符是否能组成一个回文串. 思路:首先是奇妙的dfs序和时间戳,通过记录每个节点的dfs进出时间,可以发现某个节点的子节点的进出时间均在该节点的进出时间范围内(这是很直观的dfs的性质),这样可以把树形结构转变为线性结构,方便进行各种处理.dfs一遍处理时间戳,每个节点的深度,并记录每个深度的节点都有哪些,此时每个深度的节点就是排好序的.然后对于一个询问,可以利用二分查找确定子节点在该层的哪一段.对于每一层,预先处理每个字符的前缀

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