[CF1168D]Anagram Paths
题意:给一棵\(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的更多相关文章
- RE:ゼロから始める文化課生活
觉得有必要在NOI之前开一篇学习内容记录. 至于为什么要取这个标题呢?也许并没有什么特殊的借口吧. 5.23 在LOJ上搬了三道原题给大家考了考,然后大家都在考试就我一个人在划水. SSerxhs 和 ...
- Codeforces VP/补题小记 (持续填坑)
Codeforces VP/补题小记 1149 C. Tree Generator 给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径. 考虑括号序列维护树的路径信息和,是将左括号看做 ...
- [LeetCode] Binary Tree Paths 二叉树路径
Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...
- [LeetCode] Valid Anagram 验证变位词
Given two strings s and t, write a function to determine if t is an anagram of s. For example, s = & ...
- [LeetCode] Unique Paths II 不同的路径之二
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...
- [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 ...
- 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 ...
- leetcode : Binary Tree Paths
Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...
- UVA 10564 Paths through the Hourglass[DP 打印]
UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...
随机推荐
- ceph-性能调优
Ceph 参数性能调优https://blog.csdn.net/changtao381/article/details/49907115这篇文章对我的环境有较大帮助 ceph优化记录 ceph.co ...
- Oracle_管理控制文件和日志文件
控制文件: 控制文件在数据库创建时被自动创建,并在数据库发生物理变化时更新.控制文件被不断更新,并且在任何时候都要保证控制文件是可用的.只有Oracle进程才能安全地更新控制文件的内容,所以,任何时候 ...
- jmeter3.0+ant1.10+jenkins实现接口自动化并发送邮件
有很多关于接口自动化的文章,此篇仅用于记录自己的学习用.使用jmeter3.0+ant1.10+jenkins2.实现接口自动化并发送邮件,本篇是用的编写build文件来实现发送邮件,也可以用jenk ...
- Python笔记(十六)_else语句、with语句
else的多种用法 1.try except + else:检测到代码无异常,才执行else 例如: def func(num): count=num//2 while count>1: if ...
- Android深度探索-卷1第九章心得体会
在android系统中使用Linux 驱动有两种方式一种是通过传统的方式直接与Lmux 驱动交互,如,直接读写设备文件的数据.另外一种是Android特有的,就是通过HAL 模块.HAL 模块本质是通 ...
- 20190818 On Java8 第八章 复用
第八章 复用 组合语法 初始化引用有四种方法: 当对象被定义时.这意味着它们总是在调用构造函数之前初始化. 在该类的构造函数中. 在实际使用对象之前.这通常称为延迟初始化.在对象创建开销大且不需要每次 ...
- 【Jmeter】利用Jmeter+ant+Jenkins 搭建 接口&性能测试 持续集成平台
https://www.jianshu.com/p/6ab73a95d53e https://yq.aliyun.com/articles/664329
- JS原型链详解
最近面试被问到了就决定好好深入理解原型链 对象 要清楚原型链,首先要弄清楚对象: 普通对象 最普通的对象:有__proto__属性(指向其原型链),没有prototype属性. 原型对象(person ...
- P2737 [USACO4.1]麦香牛块Beef McNuggets
题目描述 农夫布朗的奶牛们正在进行斗争,因为它们听说麦当劳正在考虑引进一种新产品:麦香牛块.奶牛们正在想尽一切办法让这种可怕的设想泡汤.奶牛们进行斗争的策略之一是“劣质的包装”.“看,”奶牛们说,“如 ...
- luoguP1312 Mayan游戏 题解(NOIP2011)
luoguP1312 Mayan游戏 题目 #include<bits/stdc++.h> #define ll long long #define rg register #define ...