1、题目大意:给你一棵树,每个点有一个字符,然后我们定义1的深度是1,然后1的儿子深度是2...

然后有一个询问,询问以i为根节点的子树,然后深度是k的那层的所有字符,可否组成一个回文串

2、分析:首先来考虑一下回文串的性质,有什么性质呢,就是里面出现次数为奇数次的点一定不会超过1个,

否则我们一定可以弄出回文串,对吧

那么我们离线处理这个东西,我们首先建立dfs序线段树,线段树里啥也别存,然后我们将询问的操作按k的大小排序

对于k相同的操作,我们在一起处理,k最多不会超过n,对吧,我们怎么处理呢,首先线段树里的空的,

线段树里的每一个节点都是一个存26个字符的出现次数的数组

我们把所有第k层的数的字符都扔进线段树,那么我做这些询问的时候,我可以找到一颗子树对应的区间,对吧

但是这个区间里只有第k层的数在这里面存着,那么我查询这个区间就相当于查询以i为根节点的子树,深度是k的那层

对吧,之后我们返回一个存26个字符的出现次数的数组。但是这样的时间复杂度是26nlogn的对吧,虽然可以卡过,

但是还是保险的好。。。我们怎么办呢,状压,我们利用异或的半加性质,我们可以把线段树的每一个节点改成状压的

仔细想一下。。

然后我们的复杂度退化到nlogn

这样就可以完美的通过了,(最不习惯写离线的算法了

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
int head[600000], ne[600000], v[600000];
int first[600000], nx[600000];
int le[600000], ri[600000], ll;
char str[600000];
int tot;
int ans[600000];
struct node{
    int num, dep, id;
    bool operator < (const node& rhs) const{
        return dep < rhs.dep;
    }
};
node a[600000];
struct segment_tree{
    int q[2500000];
    int x, y;
    inline void add(int l, int r, int o){
        if(l == r && l == x){
            q[o] = y;
            return;
        }
        int mid = (l + r) / 2;
        if(x <= mid) add(l, mid, 2 * o);
        if(x > mid) add(mid + 1, r, 2 * o + 1);
        q[o] = q[2 * o] ^ q[2 * o + 1];
        return;
    }
    inline int query(int l, int r, int o){
        if(x <= l && r <= y){
            return q[o];
        }
        int mid = (l + r) / 2;
        int ret = 0;
        if(x <= mid) ret ^= query(l, mid, 2 * o);
        if(y > mid) ret ^= query(mid + 1, r, 2 * o + 1);
        return ret;
    }
} wt;
inline void dfs(int x, int h){
    nx[x] = first[h];
    first[h] = x;
    le[x] = ++ ll;
    for(int i = head[x]; i != -1; i = ne[i]){
        dfs(v[i], h + 1);
    }
    ri[x] = ll;
    return;
}
int main(){
    memset(head, -1, sizeof(head));
    memset(first, -1, sizeof(first));
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 2; i <= n; i ++){
        scanf("%d", &v[i]);
        ne[i] = head[v[i]];
        head[v[i]] = i;
        v[i] = i;
    }
    dfs(1, 1);
    scanf("%s", str);
    for(int i = 1; i <= m; i ++){
        scanf("%d%d", &a[i].num, &a[i].dep);
        a[i].id = i;
    }
    sort(a + 1, a + m + 1);
    int i = 1;
    for( ; i <= m; ){
        int height = a[i].dep;
        for(int j = first[height]; j != -1; j = nx[j]){
            wt.x = le[j];
            wt.y = (1 << (str[j - 1] - 'a'));
            wt.add(1, n, 1);
        }
        for( ; i <= m && a[i].dep == height; i ++){
            wt.x = le[a[i].num];
            wt.y = ri[a[i].num];
            int hh = wt.query(1, n, 1);
            int cnt = 0;
            for(int k = 0; k <= 25; k ++) if(((1 << k) & hh)){
                cnt ++;
            }
            if(cnt > 1) ans[a[i].id] = 0;
            else ans[a[i].id] = 1;
        }
        for(int j = first[height]; j != -1; j = nx[j]){
            wt.x = le[j];
            wt.y = 0;
            wt.add(1, n, 1);
        }
    }
    for(int j = 1; j <= m; j ++){
        if(ans[j] == 1) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
} 

CF570D——Tree Requests的更多相关文章

  1. 解题:CF570D Tree Requests

    题面 DSU on tree确实很厉害,然后这变成了一道裸题(逃 还是稍微说一下流程吧,虽然我那个模板汇总里写过 DSU on tree可以以$O(n\log n)$的复杂度解决树上子树统计问题,它这 ...

  2. CF570D Tree Requests

    离线 + 树状数组 如果子树中的一个深度的所有点中有两个以上的字母出现了奇数次,那么这个询问的答案就是$No$,其他的情况吧都是$Yes$. 由于只有$26$个字母,我们可以考虑暴力检验,把树映射到$ ...

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

    D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  4. CF 570 D. Tree Requests

    D. Tree Requests http://codeforces.com/problemset/problem/570/D 题意: 一个以1为根的树,每个点上有一个字母(a-z),每次询问一个子树 ...

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

    http://codeforces.com/problemset/problem/570/D Tree Requests time limit per test 2 seconds memory li ...

  6. Codeforces 570D - Tree Requests(树上启发式合并)

    570D - Tree Requests 题意 给出一棵树,每个节点上有字母,查询 u k,问以 u 为根节点的子树下,深度为 k 的所有子节点上的字母经过任意排列是否能构成回文串. 分析 一个数组 ...

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

    链接:http://codeforces.com/problemset/problem/570/D D. Tree Requests time limit per test 2 seconds mem ...

  8. codeforces 570 D. Tree Requests (dfs)

    题目链接: 570 D. Tree Requests 题目描述: 给出一棵树,有n个节点,1号节点为根节点深度为1.每个节点都有一个字母代替,问以结点x为根的子树中高度为h的后代是否能够经过从新排序变 ...

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

    链接 题解链接:点击打开链接 题意: 给定n个点的树.m个询问 以下n-1个数给出每一个点的父节点,1是root 每一个点有一个字母 以下n个小写字母给出每一个点的字母. 以下m行给出询问: 询问形如 ...

随机推荐

  1. BZOJ3557: [Ctsc2014]随机数

    orz神犇们 clj(pw CCfCtsC2014) zyh cjj pyx vfk 吐槽一句对拍的时候发现这几份代码输出不一样. 每个数看成模2意义下的多项式: \[M_k\equiv x^kM_0 ...

  2. SQL Server编程(03)自定义存储过程

    存储过程是一组预编译的SQL语句,它可以包含数据操纵语句.变量.逻辑控制语句等. 存储过程允许带参数: 输入参数:可以在调用时向存储过程传递参数,此类参数可用来向存储过程中传入值(可以有默认值) 输出 ...

  3. 使用MVC过滤器保存操作日志

    //定义过滤器 public class  LogAttribute : ActionFilterAttribute { /// <summary> /// 以逗号间隔 /// </ ...

  4. MySQL的mysqldump工具的基本用法

    导出要用到MySQL的mysqldump工具,基本用法是:    shell> mysqldump [OPTIONS] database [tables]    如果你不给定任何表,整个数据库将 ...

  5. e_msg_c_as_register_req-注册存储过程

    TOP:BEGIN #Routine body goes here... IF EXISTS ( SELECT * FROM `global_account` WHERE `plantform_id` ...

  6. 测试LVS+Keepalived高可用负载均衡集群

    测试LVS+Keepalived高可用负载均衡集群 1. 启动LVS高可用集群服务 此时查看Keepalived服务的系统日志信息如下: [root@localhost ~]# tail -f /va ...

  7. vim 使用技巧

    2014-11-22 更新 文件abc 1,需要编辑abc的第三行 vim +3 abc 2,需要查询abc文件中的test字符 vim +/test abc 3,创建三个文件 aa bb cc vi ...

  8. hdu5024 Wang Xifeng's Little Plot (水

    http://acm.hdu.edu.cn/showproblem.php?pid=5024 网络赛 Wang Xifeng's Little Plot Time Limit: 2000/1000 M ...

  9. C生成随机数,奇葩问题

    今天需要生成一个随机数,奇怪的问题发生了. #include <stdio.h> #include <stdlib.h> #include <time.h> #de ...

  10. Object&&String学习

    Object类 列表项 String类 常用方法 构造方法 public String() public String(byte[] bytes) public String(byte[]bytes, ...