[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? 如果有的话,输出字典序最小的路径 ...
随机推荐
- linux新建用户并修改提示符
1 新建用户 # useradd –d /home/ap/testapp -m testapp 此命令创建了一个用户testapp ,其中-d和-m选项用来为登录名testapp 产生一个主目录/ho ...
- 【ABAP系列】SAP ABAP常用函数总结第一篇
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP常用函数总结第一 ...
- Thread -线程的两种创建方式
package cn.learn.thread.Thread; /* 实现Runnable必须重写run()方法,一般推荐用Runnable实现 */ public class RunnableImp ...
- Codeforces 433A (背包)
题面 传送门 真是令人胃疼的题面 我不管,我要把苹果都给雪菜!(滑稽)(冬马党不要打我) 分析 突然感觉这题跟今年NOIP Day1T2有点像,都是根据数加减来构造背包,只不过这题是01背包而不是完全 ...
- HDU 6386 Age of Moyu (最短路+set)
<题目链接> 题目大意:给定一张无向图,有n个点m条边,从一条边到另一条边,如果两边的指不同 花费就要+1,如果相同就不需要花费. 先从1走到n问最小花费是多少.(第一条边的花费都是1) ...
- android 完全退出应用程序(经过严格验证)
今天解决了如何彻底结束Android应用程序的方法.网上有很多的参考方法,什么finish():android.os.Process.killProcess(android.os.Process.my ...
- topic模式下的收发
生产者: import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='lo ...
- Java 8实战之读书笔记一:内容简介
本书的主要内容如下: 如何使用Java 8新增的强大特性 如何编写能有效利用多核架构的程序 重构.测试和调试 怎样高效地应用函数式编程 目录: 第一部分 基础知识 第1 章 为什么要关心Jav ...
- 一、表单和ajax中的post请求&&后台获取数据方法
一.表单和ajax中的post请求&&后台获取数据方法 最近要做后台数据接收,因为前台传来的数据太过于混乱,所以总结了一下前台数据post请求方法,顺便写了下相对应的后台接收方法. 前 ...
- 二、jquery Try{}catch(e){}
一.Try{}catch(e){} try{ $.each($("div"),function(i,item){ if(...){ throw("异常信息"); ...