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<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #define pa pair<int,int>
12 #define mp(a,b) make_pair(a,b)
13 using namespace std;
14 typedef long long LL;
15
16 inline int read() {
17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
18     for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f;
19 }
20
21 const int N = 500005;
22
23 int head[N], nxt[N], to[N], En;
24 int fa[N], siz[N], son[N], deth[N], ans[N], cnt[N][27], ch[N];
25 char s[N];
26 vector< pa > q[N];
27
28 void add_edge(int u,int v) {
29     ++En; to[En] = v; nxt[En] = head[u]; head[u] = En;
30 }
31
32 void dfs(int u,int fa) {
33     siz[u] = 1;
34     deth[u] = deth[fa] + 1;
35     for (int i=head[u]; i; i=nxt[i]) {
36         int v = to[i];
37         dfs(v, u);
38         siz[u] += siz[v];
39         if (!son[u] || siz[son[u]] < siz[v]) son[u] = v;
40     }
41 }
42
43 void add(int u) {
44     cnt[deth[u]][ch[u]] ++;
45 }
46 void Calc(int u) {
47     add(u);
48     for (int i=head[u]; i; i=nxt[i]) Calc(to[i]);
49 }
50 void Clear(int u) {
51     cnt[deth[u]][ch[u]] --;
52     for (int i=head[u]; i; i=nxt[i]) Clear(to[i]);
53 }
54
55 void solve(int u,bool c) {
56     for (int i=head[u]; i; i=nxt[i])
57         if (to[i] != son[u]) solve(to[i], 0);
58     if (son[u]) solve(son[u], 1);
59
60     for (int i=head[u]; i; i=nxt[i])
61         if (to[i] != son[u]) Calc(to[i]);
62     add(u);
63
64     for (int i=0,sz=q[u].size(); i<sz; ++i) {
65         int flag = 0, id = q[u][i].second, h = q[u][i].first;
66         for (int j=0; j<26; ++j) if (cnt[h][j] & 1) flag ++;
67         ans[id] = (flag <= 1);
68     }
69
70     if (!c) Clear(u);
71 }
72
73 int main() {
74     int n = read(), Q = read();
75     for (int i=2; i<=n; ++i) {
76         int u = read();
77         add_edge(u, i);
78     }
79     scanf("%s",s + 1);
80     for (int i=1; i<=n; ++i) ch[i] = s[i] - ‘a‘;
81     for (int i=1; i<=Q; ++i) {
82         int v = read(), h = read();
83         q[v].push_back(mp(h, i));
84     }
85     dfs(1, 0);
86     solve(1, 1);
87     for (int i=1; i<=Q; ++i) puts(ans[i] ? "Yes" : "No");
88     return 0;
89 }

原文地址:https://www.cnblogs.com/mjtcn/p/9711918.html

时间: 2024-12-12 06:23:13

CF 570 D. Tree Requests的相关文章

codeforces 570 D. Tree Requests (dfs)

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

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 570 D Tree Requests

题意:给出一棵树.每一个结点都有一个字母,有非常多次询问,每次询问.以结点v为根的子树中高度为h的后代是否可以经过调整变成一个回文串. 做法: 推断能否够构成一个回文串的话,仅仅须要知道是否有大于一个的奇数数目的字母就可以.为了非常快的訪问到一个区间.记录前缀和就可以.为了省内存,状压奇偶就可以. 为了非常快的找到以结点v为根的子树中高度为h的后代,须要dfs整棵树.然后记录每一个结点第一次訪问它的时间戳以及离开它的时间戳,就能够二分出来. 为了省内存,能够离线处理询问. #include<ma

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

CF570D:Tree Requests

传送门 DFS重标号+二分 打比赛的时候想了很多方法..DFS序,BFS序,倍增什么的都考虑了一遍,但是几乎要么是可以维护两个区间但是代码复杂度爆炸,要么就是只能维护单一维度的信息. 这道题的具体做法就是先DFS遍历一遍,记一下每个点的出入栈时间.按照每个点的深度排序.这样就可以二分出深度,然后根据入栈的时间可以再在这个深度内二分出合适的区间.范围就是询问节点的出入栈时间. //CF 570D //by Cydiater //2016.10.14 #include <iostream> #in

CF 1260F colored tree

点分治+线段树(过不去). 把点分治换成DSU ON THE TREE 应该就能过了. 设S为∏(R[i]-L[i]+1),W[i]为(R[i]-L[i]+1). 假设有一个点u,则它对答案的贡献为∑(disu + disv) * (S / (W[u] * W[v])),条件为u和v的区间有交. 把式子拆开有两个项,分别用线段树维护即可. #include<iostream> #include<cstdio> #include<algorithm> #include&l