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 std;
const int maxn = 5e5+5;

char s[maxn];

int head[maxn],to[maxn],nxt[maxn],ecnt;

void addEdge(int u,int v)
{
    to[ecnt] = v;
    nxt[ecnt] = head[u];
    head[u] = ecnt++;
}

int qhead[maxn],qnxt[maxn];

void init()
{
    memset(head,-1,sizeof(head));
    memset(qhead,-1,sizeof(qhead));
}

struct Query
{
    int h;
    int other;
    bool ans;
}query[maxn];

void addQuery(int v,int i)
{
    qnxt[i] = qhead[v];
    qhead[v] = i;
}

bool ok(int n)
{
    while(n){
        if(n&1){
            return !(n>>1);
        }
        n>>=1;
    }
    return true;
}
int d[maxn];
int cnt[maxn];
void dfs(int u)
{
    for(int i = qhead[u]; ~i; i = qnxt[i]){
        query[i].other = cnt[query[i].h];
    }
    cnt[d[u]] ^= (1<<(s[u]-‘a‘));
    for(int i = head[u]; ~i; i = nxt[i]){
        d[to[i]] = d[u]+1;
        dfs(to[i]);
    }
    for(int i = qhead[u]; ~i; i = qnxt[i]){
        query[i].ans = ok(cnt[query[i].h]^query[i].other);
    }
}

int main()
{
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 2; i <= n; i++){
        int fa; scanf("%d",&fa);
        addEdge(fa,i);
    }
    scanf("%s",s+1);
    for(int i = 0; i < m; i++){
        int v; scanf("%d%d",&v,&query[i].h);
        addQuery(v,i);
    }
    d[1] = 1;
    dfs(1);
    for(int i = 0; i < m; i++){
        query[i].ans?puts("Yes"):puts("No");
    }
    return 0;
}
时间: 2024-11-15 18:34:46

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

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 Round #316 (Div. 2) D. Tree Requests(DFS+状态压缩)

题意:给定一棵树,n个节点.每一个节点处有一个字母,结点的深度定义为节点到根结点1的距离, 有m个询问(u.v),每次回答以结点u为根的子树的深度为v的那些节点处的字母是否能组成一个回文串,特别的,空串也是回文串. 思路:首先说明推断回文串的方法,仅仅要出现次数为奇数个字母个数不超过2.那么这些字母一定能够组成回文串. 接下来考虑将树转成线性结构. 利用dfs+时间戳将结点依照深度存入一个线性结构里,Depth[i]数组里存的是深度为i的全部结点, 那么对于询问有三种情况.一种是dep[u]>=

Codeforces Round #316 (Div. 2)

A - Elections 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,num[105],a[105][105]; 4 int main() 5 { 6 scanf("%d%d",&n,&m); 7 for(int i=1;i<=m;i++) 8 { 9 int item=1; 10 for(int j=1;j<=n;j++) 11 { 12 scanf("%d&

Codeforces Round #540 (Div. 3) F1. Tree Cutting (Easy Version) 【DFS】

任意门:http://codeforces.com/contest/1118/problem/F1 F1. Tree Cutting (Easy Version) time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You are given an undirected tree of nn vertices. Some vert

Codeforces Round #629 (Div. 3) E. Tree Queries(lca题)

https://codeforces.com/contest/1328/problem/E E. Tree Queries You are given a rooted tree consisting of nn vertices numbered from 11 to nn. The root of the tree is a vertex number 11. A tree is a connected undirected graph with n−1n−1 edges. You are

Codeforces Round #353 (Div. 2) D. Tree Construction (二分,stl_set)

题目链接:http://codeforces.com/problemset/problem/675/D 给你一个如题的二叉树,让你求出每个节点的父节点是多少. 用set来存储每个数,遍历到a[i]的时候查找比a[i]大的数的位置,然后插入,而父亲就是刚好比a[i]小的数或刚好大的数. 然后讨论是哪一个数. 比如给你3 1 2 ,如图 1的父亲是3 ,2的父亲是1. 那我其实只要找左边或右边出现最晚的数就行了,用pair的first表示a[i],second表示出现的顺序i. 1 #include

数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction

Tree Construction Problem's Link ---------------------------------------------------------------------------- Mean: 给定n个数,按照构造Binary Search Tree的方式来构造BST树,按顺序输出每一个非root结点的父节点的值. analyse: 构造BST树最坏情况下时间复杂度为O(n),肯定会超时. 注意到只需要输出结点的父节点的值,不需要真的构造BST树. 插到第i

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. 换下思路,事实上每次询问所改变的字符都会保留到下一次.也就是下一次的次数就会受到上一次的影响,那么我仅仅要就算出第一次的