题意:给一棵\(n\)个节点的二叉树,每条边上有一个小写字母或者\(?\),\(q\)次修改操作,每次修改某条边上的字符,问修改后是否存在一种方案,使得给所有\(?\)填上小写字母后,所有叶子到根的路径字符串经重排后是否能全部相同,若能,还需要求出每种字符在这个字符串里的最多出现次数。

题解:考虑怎样处理单次询问。

首先显然每个叶子节点的深度必须是一样的,记为\(dep\)。

初步的想法显然是计算出根到每个叶子节点中每一种字符(\(?\)除外)出现的最大次数,设\(26\)种字符出现的最大次数总和为\(sum\),那么有合法方案当且仅当\(dep \le sum\)。但是这样是假的,因为\(?\)不独立。考虑修改上述算法,其实只要对以每一个节点为根的子树都用上述算法判断一遍是否合法即可。

证明:必要性显然。

充分性只要证明,对于任意一种最终的字符串,只要对于每个字符都满足字符串中这种字符的出现次数\(\ge\)每条根到叶子的路径中这种字符出现的最大次数,那么就是一个合法的字符串。这能很容易地通过按树深度归纳证明。

以上证明过程也告诉了我们怎样计算最大出现次数。

考虑怎样处理修改。显然可以ddp可以发现,对于只有一个儿子的节点,可以把它和儿子缩起来。这样树的深度会变成\(O(\sqrt n)\)级别的。证明:设\(s_i\)为深度为\(i\)的节点数,那么第\(i\)层没有被缩完的话需要满足\(s_i>s_{i-1}\),所以最坏情况下\(s=1,2,3,...,O(\sqrt n)\)。因为保证了最大度数为\(2\),所以更新dp值的时候暴力就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N = 150010;
typedef vector<int> vi;
#define pb push_back int gi() {
int x = 0, o = 1;
char ch = getchar();
while((ch < '0' || ch > '9') && ch != '-') {
ch = getchar();
}
if(ch == '-') {
o = -1, ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0', ch = getchar();
}
return x * o;
} int n, q, fa[N], len[N], id[N], cnt[N][26], ban = 0, sum[N], f[N][26];
vi E[N], G[N];
char c[N]; int dfs(int u) {
int son = 0;
for(auto v : E[u]) {
++son;
dfs(v);
if(len[u] && len[u] != len[v] + 1) {
while(q--) {
puts("Fou");
}
exit(0);
}
len[u] = len[v] + 1;
id[u] = id[v];
}
if(son != 1 || !u) {
id[u] = u;
for(auto v : E[u]) {
fa[id[v]] = u, G[u].pb(id[v]);
}
}
return id[u];
} void upd(int u, int c, int w) {
cnt[u][c] += w;
for(int x = fa[u]; ~x; x = fa[x]) {
ban -= sum[x] > len[x];
sum[x] -= f[x][c];
f[x][c] = 0;
for(auto v : G[x]) {
f[x][c] = max(f[x][c], f[v][c] + cnt[v][c]);
}
sum[x] += f[x][c];
ban += sum[x] > len[x];
}
} int main() {
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
cin >> n >> q;
for(int i = 2; i <= n; i++) {
E[gi()].pb(i), c[i] = getchar();
}
E[0].pb(1);
dfs(0);
--len[0];
fa[0] = -1;
for(int i = 2; i <= n; i++) if(c[i] != '?') {
upd(id[i], c[i] - 'a', 1);
}
while(q--) {
int u = gi();
if(c[u] != '?') {
upd(id[u], c[u] - 'a', -1);
}
c[u] = getchar();
if(c[u] != '?') {
upd(id[u], c[u] - 'a', 1);
}
if(ban) {
puts("Fou");
} else {
cout << "Shi ";
int ans = 0;
for(int i = 0; i < 26; i++) {
ans += (i + 1) * (f[0][i] + len[0] - sum[0]);
}
cout << ans << '\n';
}
}
return 0;
}

[CF1168D]Anagram Paths的更多相关文章

  1. RE:ゼロから始める文化課生活

    觉得有必要在NOI之前开一篇学习内容记录. 至于为什么要取这个标题呢?也许并没有什么特殊的借口吧. 5.23 在LOJ上搬了三道原题给大家考了考,然后大家都在考试就我一个人在划水. SSerxhs 和 ...

  2. Codeforces VP/补题小记 (持续填坑)

    Codeforces VP/补题小记 1149 C. Tree Generator 给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径. ​ 考虑括号序列维护树的路径信息和,是将左括号看做 ...

  3. [LeetCode] Binary Tree Paths 二叉树路径

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  4. [LeetCode] Valid Anagram 验证变位词

    Given two strings s and t, write a function to determine if t is an anagram of s. For example, s = & ...

  5. [LeetCode] Unique Paths II 不同的路径之二

    Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...

  6. [LeetCode] Unique Paths 不同的路径

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  7. Leetcode Valid Anagram

    Given two strings s and t, write a function to determine if t is an anagram of s. For example,s = &q ...

  8. leetcode : Binary Tree Paths

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  9. UVA 10564 Paths through the Hourglass[DP 打印]

    UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...

随机推荐

  1. http://research.google.com/archive/mapreduce.html

    http://research.google.com/archive/mapreduce.html

  2. 124、TensorFlow替换函数

    # tf.device给你了很多可伸缩性在TensorFlow的计算图中选择放置你的单独的操作 # 在许多的情况下,有很多启发可以工作的很好 # 例如tf.train.replica_device_s ...

  3. input只输入数字和小数后两位

    html:<input  name="" type="tel" value="" placeholder="请输入金额&qu ...

  4. python实现操作mysql数据库

    实现代码如下: #mysql数据库的查询等 import pymysql from xctest_tools.xc_ReadFile.get_ReadTxt import * class mysql: ...

  5. 《JAVA设计模式》之外观模式(Facade)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述门面(Facade)模式的: 门面模式是对象的结构模式,外部与一个子系统的通信必须通过一个统一的门面对象进行.门面模式提供一个高层次的接口 ...

  6. 洛谷 P3374 【模板】树状数组 1(单点加,区间和)

    题目链接 https://www.luogu.org/problemnew/show/P3374 树状数组 树状数组最基本的就是求区间和. 维护: 空间复杂度:O(n) 时间复杂度(区间和,单点修改) ...

  7. ZOJ 2706 Thermal Death of the Universe

    Thermal Death of the Universe Time Limit: 10 Seconds                                     Memory Limi ...

  8. vue2.0在IE11无法打开的解决办法

    npm 安装bebel-polyfill npm install --save-dev babel-polyfill 在webpack.base.conf.js文件中将 module.exports ...

  9. IEnumerable和IEnumerator 详解 分类: C# 2014-12-05 11:47 18人阅读 评论(0) 收藏

    原:<div class="article_title"> <span class="ico ico_type_Original">&l ...

  10. Java集合、IO流、线程知识

    一.集合: 1. 集合框架: 1)Collection (1)List:有序的,有索引,元素可重复. (add(index, element).add(index, Collection).remov ...