题目链接:\(\color{Purple}\texttt{P9683 A Certain Forbidden Index}\)

填坑。提供一个相对好写的做法。

考虑把一堆不交的区间绑在一起问(即先询问这些区间的并,判断答案是否在里面):对于一个区间,能与它绑在一起的区间最多只有 \(1\) 个是与它同一层的。

于是我们想到一个比较原始的做法:因为 \([1,2^k]\) 没有任何区间可以合并,所以放最后作为单独一块问;从线段树的顶端按照 BFS 序往下询问,如果该区间 \([l,r]\) 没有进行过标记(记这种区间为“初始区间”),按以下方式处理:标记它,如果它是作为左儿子被问到的(反之同理),那么就不断往右找下一层且它们的并集是一个区间的区间 \([l_1,r_1]\)(即满足 \(l_1=r+1\)),然后 \([l,r]\leftarrow[l_1,r_1]\),对 \([l_1,r_1]\) 进行标记;这样能获得不少的块并且答案已经很优。加上对 \(k=1\) 的特判可以做到 \(63\mathrm{pts}\):笔者考场上使用的是该做法,已经得到了一个非常可观的分数。

注:对于这种做法,如果对块内相邻元素连边,在整棵线段树上这些边就可以构成很多交叉的 X 型(读者可以自行理解一下)。

但是此时答案还不是最优的。考虑是否可以合并一些区间:我们观察到,对于一些左 / 右端点在正中间的作为右 / 左儿子进行处理的区间,是可以将它所在的块和同一层那个唯一可以合并的区间所在的块合并的。例如,\(k=4\) 时,区间 \([7,8]\) 与区间 \([9,10]\) 所在的块可以合并。处理的过程中考虑一下这种情况。

事实上我们可以观察到,对于合并同一层的这种情况,我们只需处理 \([l,r]\) 满足 \(r<2^k\) 且作为右儿子询问到的“初始区间”所在的块和它右边那个同层的且可合并的区间所在的块即可。证明显然。

询问块内元素的过程可以不用像其他题解一样用二分,因为我们观察到如果一个块的大小如果不超过 \(2\),那么二分跟朴素做法的没有区别——实际上块越小两种做法的区别越小。又因为是按照 BFS 序从上往下问,感性理解一下就可以得知越往下问块越小而且数量越多。实测可以获得 \(100\mathrm{pts}\)。

如果不放心可以把所有块全部预处理出来然后按照块的大小降序排序询问。但是这个做法会在 \(k=14\) 的时候超时,所以选用前者。

示例代码(\(100\mathrm{pts}\)):

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
int query(int,int);
pii solve(int k){
vector<tuple<int,int,int,int> > q;
function<void(int,int,int)> dfs=[&](int l,int r,int w){
if(l==r)return;
q.emplace_back(l,l+r>>1,w-1,0);
q.emplace_back(l+r+1>>1,r,w-1,1);
dfs(l,l+r>>1,w-1);
dfs(l+r+1>>1,r,w-1);
}; // 按照 BFS 序处理出所有区间遍历顺序,0/1 表示左 / 右儿子
dfs(1,1<<k,k);
set<pii> t; t.emplace(1,1<<k);
vector<tuple<vector<pii>,int,int,int,int> > s;
for(auto [l,r,w,b]:q){
if(t.find(make_pair(l,r))==t.end()){
vector<pii> v; int p=(b?l:r);
for(int i=w-1;i>=0;i--){
v.emplace_back(b?p-(1<<i):p+1,b?p-1:p+(1<<i));
b?p-=(1<<i):p+=(1<<i);
} // 处理块
if(b){
bool b2=false;
if(r<(1<<k)){
b2=true,p=r;
for(int i=w;i>=0;i--){
v.emplace_back(p+1,p+(1<<i));
p+=(1<<i);
}
} // 可以与同一层的合并
if(query(l-(1<<w)+1,b2?(r<<1)-l+(1<<w):r)){
// 询问是否在整个区间,下同
for(auto [l1,r1]:v)
if(query(l1,r1))return make_pair(l1,r1);
// 询问单个区间,下同
return make_pair(l,r);
// 不在上述区间就是最后一个,下同
}
}
else if(query(l,r+(1<<w)-1)){
for(auto [l1,r1]:v)
if(query(l1,r1))return make_pair(l1,r1);
return make_pair(l,r);
}
for(auto [l1,r1]:v)t.emplace(l1,r1);
t.emplace(l,r); // 使用 std::set 打标记
}
}
return make_pair(1,1<<k); // 都不是上述区间
}

洛谷 P9683 A Certain Forbidden Index 题解的更多相关文章

  1. 洛谷P1854 花店橱窗布置 分析+题解代码

    洛谷P1854 花店橱窗布置 分析+题解代码 蒟蒻的第一道提高+/省选-,纪念一下. 题目描述: 某花店现有F束花,每一束花的品种都不一样,同时至少有同样数量的花瓶,被按顺序摆成一行,花瓶的位置是固定 ...

  2. HAOI2006 (洛谷P2341)受欢迎的牛 题解

    HAOI2006 (洛谷P2341)受欢迎的牛 题解 题目描述 友情链接原题 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之 ...

  3. 洛谷P3412 仓鼠找$Sugar\ II$题解(期望+统计论?)

    洛谷P3412 仓鼠找\(Sugar\ II\)题解(期望+统计论?) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327573 原题链接:洛谷P3412 ...

  4. 洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速$dp\&Floyd$)

    洛谷P3502 [POI2010]CHO-Hamsters感想及题解(图论+字符串+矩阵加速\(dp\&Floyd\)) 标签:题解 阅读体验:https://zybuluo.com/Junl ...

  5. BZOJ4946 & 洛谷3826 & UOJ318:[NOI2017]蔬菜——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4946 https://www.luogu.org/problemnew/show/P3826 ht ...

  6. 洛谷1578:[WC2002]奶牛浴场——题解

    https://www.luogu.org/problemnew/show/P1578#sub 由于John建造了牛场围栏,激起了奶牛的愤怒,奶牛的产奶量急剧减少.为了讨好奶牛,John决定在牛场中建 ...

  7. 洛谷P2460 [SDOI2007]科比的比赛(题解)(贪心+搜索)

    科比的比赛(题解)(贪心+搜索) 标签:算法--贪心 阅读体验:https://zybuluo.com/Junlier/note/1301158 贪心+搜索 洛谷题目:P2460 [SDOI2007] ...

  8. 洛谷 P1146 【硬币翻转】题解

    很久很久之前做过的一道题 翻n-1枚硬币,就是有一枚不翻,也可以理解为翻一枚 直接上程序,看程序说话 #include<iostream> using namespace std; ; b ...

  9. 洛谷P1972 [SDOI2009]HH的项链 题解

    [SDOI2009]HH的项链 题目背景 无 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不 ...

  10. 洛谷 p1352 没有上司的舞会 题解

    P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员 ...

随机推荐

  1. MySQL运维9-Mycat分库分表之枚举分片

    一.枚举分片 通过在配置文件中配置可能的枚举值,指定数据分布到不同数据节点上,这种方式就是枚举分片规则,本规则适用于按照省份,性别,状态拆分数据等业务 二.枚举分片案例 枚举分片需求:现有 tb_en ...

  2. 【UniApp】-uni-app-pinia存储数据

    前言 经过上个章节的介绍,大家可以了解到 uni-app-数据缓存 的基本使用方法 那本章节来给大家介绍一下 uni-app-pinia存储数据 的基本使用方法 经过我这么多篇章的介绍,我发现大家环境 ...

  3. TensorFlow C++ 初始化 Tensor 内存 到GPU 内存

    最近使用TensorFlow C++版本实现神经网络的部署,我通过GPU 处理得到网络的输入值,因此输入值在GPU内存上保存, TF 输入tensor 的调用语句为 Tensor inputTenso ...

  4. 数字孪生融合GIS系统将为交通领域带来什么改变?

    随着科技的不断发展,数字孪生和GIS技术正成为交通领域的新宠.数字孪生是指通过数学建模.数据采集和实时仿真等技术手段,将实体世界与数字世界相互关联,形成一个全新的虚拟系统.而GIS(地理信息系统)则是 ...

  5. Ubuntu apt-get 的使用

    在Ubuntu中,可以使用apt-get命令来管理软件包.下面是一些常见的apt-get命令及其用法: 安装软件包: sudo apt-get install <package> 其中,& ...

  6. .net Core中间件实战

    新建一个ASP.NET Core Web Application 项目选中空模板 然后为项目添加一个Microsoft.Extensions.Logging.Console 由于我用的.net cor ...

  7. 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 14. 使用GameplayTag实现防守反击技能

    斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本篇文章对应Lecture 17 - GameplayTags, 70节.本文将会结合前几节课使用的能力系统和G ...

  8. 自签证书https

    1.下载编译好的openssl. http://slproweb.com/products/Win32OpenSSL.html 下载完成后运行安装: 记住你安装到的目录,等下打开这个文件夹(小贴士:最 ...

  9. MindSpore!这款刚刚开源的深度学习框架我爱了!

    [摘要] 本文主要通过两个实际应用案例:一是基于本地 Jupyter Notebook 的 MNIST 手写数据识别:二是基于华为云服务器的 CIFAR-10 图像分类,对开源框架 MindSpore ...

  10. openGemini v0.2.0版本正式发布:5大特性全面增强

    摘要:openGemini是华为云面向物联网和运维监控场景开源的一款云原生分布式时序数据库,兼容InfluxDB API,具有高性能.高并发.高扩展等特点. openGemini是华为云面向物联网和运 ...