比赛链接

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 超详细)的更多相关文章

  1. 「CSP-S模拟赛」2019第四场

    「CSP-S模拟赛」2019第四场 T1 「JOI 2014 Final」JOI 徽章 题目 考场思考(正解) T2 「JOI 2015 Final」分蛋糕 2 题目 考场思考(正解) T3 「CQO ...

  2. #10471. 「2020-10-02 提高模拟赛」灌溉 (water)

    题面:#10471. 「2020-10-02 提高模拟赛」灌溉 (water) 假设只有一组询问,我们可以用二分求解:二分最大距离是多少,然后找到深度最大的结点,并且把它的\(k\)倍祖先的一整子树删 ...

  3. #10470. 「2020-10-02 提高模拟赛」流水线 (line)

    题面:#10470. 「2020-10-02 提高模拟赛」流水线 (line) 题目中的那么多区间的条件让人感觉极其难以维护,而且贪心的做法感觉大多都能 hack 掉,因此考虑寻找一些性质,然后再设计 ...

  4. 「NOIP模拟赛」数位和乘积(dp,高精)

    统计方案数,要么组合数,要么递推(dp)了. 这是有模拟赛历史以来爆炸最狠的一次 T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0 T3看错题本来简单模拟又 ...

  5. 「Vijos 1284」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔法阵

    佳佳的魔法阵 背景 也许是为了捕捉猎物(捕捉MM?),也许是因为其它原因,总之,佳佳准备设计一个魔法阵.而设计魔法阵涉及到的最关键问题,似乎就是那些带有魔力的宝石的摆放-- 描述 魔法阵是一个\(n ...

  6. 「CSP-S模拟赛」2019第一场

    目录 T1 小奇取石子 题目 考场思路 正解 T2 「CCO 2017」专业网络 题目 考场思路 题解 T3 「ZJOI2017」线段树 题目 考场思路 正解 这场考试感觉很奇怪. \(T1.T2\) ...

  7. 「CSP-S模拟赛」2019第二场

    目录 T1 Jam的计数法 题目 考场思路(正解) T2 「TJOI / HEOI2016」排序 题目 考场思路(假正解) 正解 T3 「THUWC 2017」随机二分图 题目 考场思路 正解 这场考 ...

  8. 「CSP-S模拟赛」2019第三场

    目录 T1 「POI2007」山峰和山谷 Ridges and Valleys 题目 考场思路(几近正解) 正解 T2 「JOI 2013 Final」 现代豪宅 题目 考场思路(正解) T3 「SC ...

  9. 「NOIP模拟赛」Round 2

    Tag 递推,状压DP,最短路 A. 篮球比赛1 题面 \(Milky\ Way\)的代码 #include <cstdio> const int N = 2000, xzy = 1e9 ...

  10. Solution -「牛客 NOIP 模拟赛」打拳

    \(\mathcal{Description}\)   现 \(2^n\) 个人进行淘汰赛,他们的战力为 \(1\sim 2^n\),战力强者能战胜战力弱者,但是战力在集合 \(\{a_m\}\) 里 ...

随机推荐

  1. 光刻机巨头ASML公布了其最新的品牌短片《站在巨人的肩膀上》

    光刻机巨头ASML公布了其最新的品牌短片<站在巨人的肩膀上>: 荷兰光刻机:ASML使用AI工具midjourney和runway制作宣传片 这个时长1分50秒短片的特别地方在于,它是完全 ...

  2. 修改linux系统时间由UTC改为CST(中国上海)时区

    Ubuntu系统 1. 将时间改为CST的中国上海时间: 命令: sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 或: sudo ...

  3. jQuery Eazyui的学习和使用(一)

    工作需要,需要学习使用据说非常简单好用的前端框架-----Eazyui 先看看简介吧:"jQuery EasyUI 是一个基于 jQuery 的框架,集成了各种用户界面插件.jQuery E ...

  4. 飞书Webhook触发操作指南,实现事件驱动型工作流自动化

    本文提供了利用数据触发Feishu Webhook的具体操作指南,包括Webhook的设置以及编写触发代码的方法,为读者提供了实践参考,希望能帮助解决你目前遇到的问题. 描述 用于使用数据触发 Fei ...

  5. NOI2024 集合 题解

    给个链接:集合. 很神秘的题目.基本上看到之后就可以想到哈希. 首先想到一个比较神秘的暴力.就是对于每个询问,扫一遍所有 \(a\) 中的数出现的位置,把它弄成一个哈希值(具体怎么弄随意)存到 set ...

  6. VS常用拓展以及快捷键

    VS常用拓展以及快捷键 扩展1:Select Next Occurrence 该拓展可以当前目标.下一个目标.上一个目标,类似于Alt+鼠标拖动,但是可以在没对齐的情况下使用 安装 设置4个常用的快捷 ...

  7. JS脚本批量处理TS数据类型

    在TS开发中,经常会遇到后台数据字段比较多的情况,这时候需要一个个复制字段然后给他手动配置数据类型来完成我们的TS类型定义,相当麻烦.有什么快速的方法呢,我就目前遇到的两种情况分别写了JS脚本来处理后 ...

  8. C# 使用正则表达式 将金额转换为中文大写

    /// <summary> /// decimal转换成中文大写 /// </summary> /// <param name="number"> ...

  9. Redis、Nginx、SQLite、Elasticsearch等开源软件成功的原因及他们对IT技术人员的启示

    引言 这些年在自研产品,对于如何做好产品进行了一些思考.随着开源软件的蓬勃发展,许多开源项目已经成为IT行业的核心组成部分.像Redis.Nginx.SQLite.Elasticsearch这些知名的 ...

  10. HTML / CSS – Email Marketing HTML Template

    前言 虽然现在的 Email Client 有在进步, 但是比起 browser 还是差太远了. 假如你用 HTML5 + CSS3 的方式去写 Email Template 的话是不行的. 这篇特地 ...