「模拟赛」CSP-S 模拟 11(T2 超详细)
A.玩水 (water)
签到。发现如果要找两条路径的话,能找到的充要条件是存在一个点的上方和左方的字母相同。(即使两条走过的点截然不同的路径也符合,这时终点会成为这个点)。
即存在一个位置 \((i,j)\) 使得 \(s_{i-1,j}=s_{i,j-1}\),我们称位置 \((i,j)\) 是好位置。
扩展到三条路发现,存在上面的两个好位置就可以了,但对这两个位置有要求:
- 两点相邻,即以下情形:

或者 同一列上相邻
- 两个好位置 \((i_1,j_1),(i_2,j_2)\) 满足 \(i_2>i_1,j_2>j_1\)
B. AVL 树
贪心,思路其实很简单,只不过不好实现。
发现尽量留下小的节点比较优,于是中序遍历,每到一个节点则求出若留下它则至少要留多少个点(设这个数量为 \(x\)),比较 \(x\) 与 \(k\),若 \(x<k\) 则这个点可以留下来,标记上。
考虑具体如何查询一个点留下来至少要留的点的个数。
对于查询:
发现若一颗 AVL 树的高度若是确定的,则它最少包含的节点数量可求:
可以预处理出来 \(f[i]\),表示深度为 i 的AVL树,节点数至少多大。有递推式 \(f[i]=f[i−1]+f[i−2]+1\),可以看作一边深度为 i−1,一边深度为 i−2,在上面接上了根节点。
那么查询求出一个点留下来,一直回溯它的祖先节点直到根,对于该节点是左儿子的情况计算出保留这个节点至少需要右子树中有多少个节点,即可转化成求右子树的最小高度。
我们维护每个点的 深度 \(dep\)、子树内最大深度 \(dmax\),dfs 预处理这两个信息即可。
还要维护每个点为根的 子树中已选点的最大深度 \(had\),和若留下该点至少需要的深度 \(ned\)。
这样询问所需点的个数就好说了,在询问点不断跳父亲回溯的过程中,当跳到的点是左儿子时,求出保留这个点,它父节点的右儿子最小高度。
具体看代码,那么现在我们还需要实时更新这些信息。
考虑更新:
每个点被选后都要不断回溯祖先节点至根节点来更新它所有祖先节点的已选子树的最大深度;
并且回溯过程中,该点为左儿子时需要更新父节点的右儿子留下来需要的最大深度,(为了保证满足 AVL 树的要求,即两儿子子树的高度差值不超过 1)
而该点为右儿子时则不用管父节点的左儿子,因为左儿子一定被我们优先考虑过是否可留下,右儿子在左儿子之后遍历到,不对左儿子有影响。
由于 AVL 树的性质,高度约为 \(\log n\),所以整体复杂度为 \(O(n\log n)\)。
具体还有很详细的代码注释:
code
#include<bits/stdc++.h>
#define mp make_pair
#define Type int
#define qr(x) x=read()
typedef __int128 INT;
typedef long long ll;
using namespace std;
inline Type read(){
char c=getchar(); Type x=0, f=1;
while(!isdigit(c)) (c=='-'?f=-1:f=1), c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48), c=getchar();
return x*f;
}
const int N = 5e5 + 5;
int n, k, root, whi[N];
int son[N][2], fa[N], f[N];
int dep[N], dmax[N];
inline void dfs(int x, int p){ dfs 预处理
dmax[x] = dep[x] = dep[p] + 1;
for(int i=0; i<2; i++){
int y = son[x][i];
if(!y) continue;
dfs(y, x);
dmax[x] = max(dmax[x], dmax[y]);
}
}
int ned[N], had[N], vis[N];
inline int query(int u){
int y = u, x = fa[u], res = 0;
while(x != -1){
if(!whi[y]) res += f[max({had[x]-1, dep[u]-1, ned[son[x][1]]})-dep[x]];// 跳到点为左儿子时,加上右儿子的贡献
y = x, x = fa[x];
}
return res;
}
inline void update(int u){ //选了一个点,更新它对祖先节点的影响
had[u] = max(had[u], dep[u]);
int y = u, x = fa[u];
while(x != -1){
had[x] = max(had[x], dep[u]);//更新子树内已选的点的最大深度
if(!whi[y] and son[x][1]) ned[son[x][1]] = max(ned[son[x][1]], had[x] - 1); //该点是左儿子,更新若选右儿子需要的最大深度
y = x, x = fa[x];
}
}
inline void DFS(int x){
if(query(x) < k){
vis[x] = true;
k--; update(x);
}
if(son[x][0] and dmax[son[x][0]] >= ned[x]){ //左子树的最大深度达得到父节点需要的就选择左子树
ned[son[x][0]] = max(ned[son[x][0]], ned[x]);
if(son[x][1]) ned[son[x][1]] = max(ned[son[x][1]], ned[x] - 1);
}
else if(son[x][1]){ //否则选择右子树
ned[son[x][1]] = max(ned[son[x][1]], ned[x]);
if(son[x][0]) ned[son[x][0]] = max(ned[son[x][0]], ned[x] - 1);
}
for(int i=0; i<2; i++){
int y = son[x][i];
if(!y) continue;
DFS(y);
}
}
signed main(){ //avl
freopen("avl.in", "r", stdin), freopen("avl.out", "w", stdout);
qr(n), qr(k);
for(int i=1; i<=n; i++){
qr(fa[i]);
if(fa[i] == -1){root = i;continue;}
whi[i] = (i < fa[i] ? 0 : 1); //判断该点是其父节点的左子树还是右子树
son[fa[i]][whi[i]] = i;
}
if(k == 1){
for(int i=1; i<=n; i++)
cout<<(i == root ? 1 : 0);
return 0;
}
dfs(root, 0);
f[1] = 1;
for(int i=2; i<=30; i++) f[i] = f[i-1] + f[i-2] + 1; //递推求深度为 i 的 AVL 树的最少节点数
DFS(root);
for(int i=1; i<=n; i++)
cout<<vis[i];
cout<<'\n';
return 0;
}
「模拟赛」CSP-S 模拟 11(T2 超详细)的更多相关文章
- 「CSP-S模拟赛」2019第四场
「CSP-S模拟赛」2019第四场 T1 「JOI 2014 Final」JOI 徽章 题目 考场思考(正解) T2 「JOI 2015 Final」分蛋糕 2 题目 考场思考(正解) T3 「CQO ...
- #10471. 「2020-10-02 提高模拟赛」灌溉 (water)
题面:#10471. 「2020-10-02 提高模拟赛」灌溉 (water) 假设只有一组询问,我们可以用二分求解:二分最大距离是多少,然后找到深度最大的结点,并且把它的\(k\)倍祖先的一整子树删 ...
- #10470. 「2020-10-02 提高模拟赛」流水线 (line)
题面:#10470. 「2020-10-02 提高模拟赛」流水线 (line) 题目中的那么多区间的条件让人感觉极其难以维护,而且贪心的做法感觉大多都能 hack 掉,因此考虑寻找一些性质,然后再设计 ...
- 「NOIP模拟赛」数位和乘积(dp,高精)
统计方案数,要么组合数,要么递推(dp)了. 这是有模拟赛历史以来爆炸最狠的一次 T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0 T3看错题本来简单模拟又 ...
- 「Vijos 1284」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔法阵
佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放-- 描述 魔法阵是一个\(n ...
- 「CSP-S模拟赛」2019第一场
目录 T1 小奇取石子 题目 考场思路 正解 T2 「CCO 2017」专业网络 题目 考场思路 题解 T3 「ZJOI2017」线段树 题目 考场思路 正解 这场考试感觉很奇怪. \(T1.T2\) ...
- 「CSP-S模拟赛」2019第二场
目录 T1 Jam的计数法 题目 考场思路(正解) T2 「TJOI / HEOI2016」排序 题目 考场思路(假正解) 正解 T3 「THUWC 2017」随机二分图 题目 考场思路 正解 这场考 ...
- 「CSP-S模拟赛」2019第三场
目录 T1 「POI2007」山峰和山谷 Ridges and Valleys 题目 考场思路(几近正解) 正解 T2 「JOI 2013 Final」 现代豪宅 题目 考场思路(正解) T3 「SC ...
- 「NOIP模拟赛」Round 2
Tag 递推,状压DP,最短路 A. 篮球比赛1 题面 \(Milky\ Way\)的代码 #include <cstdio> const int N = 2000, xzy = 1e9 ...
- Solution -「牛客 NOIP 模拟赛」打拳
\(\mathcal{Description}\) 现 \(2^n\) 个人进行淘汰赛,他们的战力为 \(1\sim 2^n\),战力强者能战胜战力弱者,但是战力在集合 \(\{a_m\}\) 里 ...
随机推荐
- 在vscode中通过修改launch.json文件为项目设置当前工作目录cwd——在launch.json文件中修改cwd变量
关于当前工作目录是什么以及其与模块搜索路径的区别可以参见下文: Python语言中当前工作目录(Current Working Directory, cwd)与模块搜索第一路径都是指什么??? --- ...
- nginx实战教程
大纲 为了让大家更快的学会,该博客中的内容录制成了视频课程:马上在线学习 1.什么是nginx Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 由 ...
- stm32 F103C8T6 4x4矩阵键盘使用
首先感谢 江科大 的stm32入门课程 受益匪浅.推荐有兴趣的朋友去看看. 先看看我用的矩阵键盘是啥样的(很常见的一种) 接线如图(其他型号根据自己需求接上GPIO口) 代码基于stm大善人的代码修改 ...
- 【客户案例】白鲸开源WhaleStudio助力某证券公司打造全面数据解决方案:探析DataOps平台革新与应用
背景 近年来随着国际形势的变化,信创产业成为我国国家战略的一部分.一直以来,一直以来,全球 ICT 产业底层标准.架构.产品.生态等要素均由国外公司或机构制定和控制,使我国 ICT 产业乃至广大用户面 ...
- 关于Springboot理解
面向对象五大基本原则 graph LR A(面向对象五大原则);B(单一职责原则);C(开放封闭原则);D(里式替换原则);E(依赖倒置原则);F(接口隔离原则); A---B;A---C;A---D ...
- Go 监控告警入门 Opentelemetry
前言 Opentelemetry 分布式链路跟踪( Distributed Tracing )的概念最早是由 Google 提出来的,发展至今技术已经比较成熟,也是有一些协议标准可以参考.目前在 Tr ...
- 2024九省联考 数学 T19
寒假有朋友打电话吐槽九省联考,看了眼数学卷子感觉非常刺激.刚开学没事干,试着做一下 \(19\). (\(17\) 分) 离散对数在密码学中有重要的应用.设 \(p\) 是素数,集合 \(X=\{1, ...
- 我的 mac 生产力工具
应用名称 说明 安装命令 Homebrew mac 上的强大包管理器 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com ...
- 【YashanDB知识库】YMP元数据阶段二报错YAS-04204
[问题分类]YMP迁移 [关键字]YMP迁移,YAS-04204 [问题描述]数据库采用最小规格部署,机器配置2C8G,使用YMP进行数据和对象迁移,在元数据阶段二创建索引时报错:YAS-04204 ...
- TS中简单实现一下依赖注入
依赖注入(Dependency Injection,DI)是一种设计模式,主要用于实现控制反转(Inversion of Control,IoC).它通过将对象的依赖关系从内部管理转移到外部容器来解耦 ...