题意:给一棵\(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. 【SpringBoot】 项目中运用的一些技巧,mybatis-plus 自动编译等(持续更新)

    前言 本文将总结项目中用到的一些springboot 的技巧,持续更新. Mybatis-Plus 的运用 使用原因: 主要是节省了Mapper层的编写,通过继承BaseMapper可以直接调用通用的 ...

  2. Vue.js的列表数据的同步更新方法

    这次给大家带来Vue.js的列表数据的同步更新方法,Vue.js列表数据同步更新方法的注意事项有哪些,下面就是实战案例,一起来看一下. 数组的 push(),pop(),shift(),unshift ...

  3. Emqtt集群搭建

    1 Emqtt简单搭建 1.1  介绍:EMQ:EMQ 2.0,号称百万级开源MQTT消息服务器,基于Erlang/OTP语言平台开发,支持大规模连接和分布式集群,发布订阅模式的开源MQTT消息服务器 ...

  4. 炫酷CSS3加载动画

    <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8&qu ...

  5. 解决bug:sprongboot2整合shiro,swagger2页面样式加载不出来问题

    问题如题: 解决思路,把shiro拦截去掉之后发现swagger-ui.html页面接在的资源如下: 因此可以推断拦截器拦截了 "/swagger-resources" " ...

  6. 这样设计 Java 异常更优雅,赶紧学!

    来源:lrwinx.github.io/2016/04/28/如何优雅的设计java异常/ 导语 异常处理是程序开发中必不可少操作之一,但如何正确优雅的对异常进行处理确是一门学问,笔者根据自己的开发经 ...

  7. 《剑指offer》面试题9 斐波那契数列 Java版

    书中方法一:递归,这种方法效率不高,因为可能会有很多重复计算. public long calculate(int n){ if(n<=0){ return 0; } if(n == 1){ r ...

  8. 8786:方格取数 (多线程dp)

    [题目描述] 设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点.在走 ...

  9. 702:Crossing River (贪心)

    [题目描述] N个人过河,一次过去2个回来一个,给出每个人所需时间,问最小过河时间. [题目链接] http://noi.openjudge.cn/ch0406/702/ [算法] 一开始想样例是怎么 ...

  10. php cookie session 深究一下

    当一个用户用浏览器访问web(www.96net.com.cn)时候,若服务器开启session_start() 服务器tmp临时目录 自动生成session_id 并放回给创建一个cookie 保存 ...