比赛链接

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. 【Vue】15 VueX

    [什么是VueX?] VueX是一个专门为Vue.js应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件状态, 以相应的规则保证按照一种可预测的方式发生改变. 即把多个组件的变量统一放到一 ...

  2. (续) gym atari游戏的环境设置问题:Breakout-v0, Breakout-v4, BreakoutNoFrameskip-v4和BreakoutDeterministic-v4的区别

    根据前文(https://www.cnblogs.com/devilmaycry812839668/p/14665072.html)我们知道: 首先是v0和v4的区别:带有v0的env表示会有25%的 ...

  3. ubuntu 安装osx 主题 转自linux公社

    繁體 你好,游客 登录 注册 搜索 首页Linux新闻Linux教程数据库技术Linux编程服务器应用Linux安全Linux下载Linux认证Linux主题Linux壁纸Linux软件数码手机电脑 ...

  4. 中电信翼康济世数据中台基于Apache SeaTunnel构建数据集成平台经验分享

    作者 | 中电信翼康工程师 代来编辑 | Debra Chen 一. 引言 Apache SeaTunnel作为一个高性能.易用的数据集成框架,是快速落地数据集成平台的基石.本文将从数据中台战略背景. ...

  5. List按需转换Map

    需求 : Mybatis的<select>返回一个List,想按照实体类其中的属性转换成Map<String, String>实现过程: 其实有很多方式,可以使用普通for循环 ...

  6. 牛客周赛 Round 4

    牛客周赛 Round 4 A-游游的字符串构造_牛客周赛 Round 4 (nowcoder.com) 先把几个\('you'\)输出,剩下的随便输出 #pragma GCC optimize(3) ...

  7. 使用sl+tmux哇娃

    0x01 背景 2岁多的小娃不肯刷牙,有时看故事书时会配合刷一会儿,但偶尔也不好使.突然想到TA,之前在电脑桌旁边捣乱时,给ta看过console中的小火车,ubuntu中安装sl命令后就可以看到,用 ...

  8. JavaScript设计模式样例二十一 —— 解释器模式

    解释器模式(Interpreter Pattern) 定义:提供了评估语言的语法或表达式的方式.目的:对于一些固定文法构建一个解释句子的解释器.场景:编译器.运算表达式计算. // 定义对于语法的断言 ...

  9. 22.11.20 ICPC合肥站 打星记录

    A,B,H签到. B题:注意区分相对误差与绝对误差!!小数相对误差小于1e-6,至少要输出十二位! G题优先队列.场上十几分钟就想出来了,表扬自己一波,留个坑位写题解. M题情况不多直接暴搜, 最后一 ...

  10. Qt 设置快捷键

    Qt设置快捷键 本文仅供本人知识总结使用,所以内容会比较浅显,不喜勿喷. 文章目录 Qt设置快捷键 一.需要的类 QShortcut 函数: 二.设置快捷键 官方文档原文翻译: 我的理解: 一.需要的 ...