看到的时候感到很不可做,因为所有的开关都要状态归零。因此可以得到两分的好成绩。

……然后 yhx-12243 说:这不是线段树优化建图吗?

于是我获得了启发,会做了……

还不是和上次一样,通过提示做出这种交互题的?

我还是太菜了

以下魔改自我的思考过程(一开始想对每一个触发器配一组开关决策下一步,然后听说用线段树直接想到一组开关决策整颗树了)

其实前半部分的思考貌似没用,直接套到整棵树上是适用的


因为状态要清零,考虑清空这个状态。

考虑每个触发器连向一个开关,来决策下一步走什么,因为和二进制有关,所以我们构造一个线段树类似的。

假设出现 \(s\) 次,记 \(L = 2^k \geq s\) 使得 \(k\) 最小。

那么我们前 \(L - s\) 次就开个到根的边,后面 \(s\) 次就可以直接走后继了。

那么如果走了 \(L\) 步,线段树内所有点都遍历到了。

注意到 \(L\) 是二的幂,跑完后所有非叶节点区间长度都是偶数,即遍历到偶数次,即清零了。这也说明了为什么不用普通线段树。

所以要把叶子结点全部扔掉,不然就会有节点只遍历到一次。如果扔掉叶子,那么就是一棵大小为 \(L - 1\) 的树。

注意特判一下最后一个点的后继是 \(0\)。

这样点数是 \(2n\) 的 (对于一个 \(s\),有 \(s \leq L < 2s\)),可以获得 \(50\) 分。

考虑优化这个,发现很多的点是没有用的,即整个区间都会再次回到根。那么要访问到这个区间的时候,不如提前回到根。即删掉这个点,父亲连向自己的边改为连向根。

但是发现优化力度不大,这是因为这道题的遍历方式使得遍历的点交错了起来。

因为最后一个点是在右边的,那么我们把线段树右边的那 \(s\) 个点取来,钦定它们是出边,然后根据先前遍历的顺序把值钦定一下就好。

我们只选了右边的点,优化力度很明显了。

对于 \(s = 5\), \(L = 8\),淡色是叶子,打钩的是有用的点。(机房没带数位板请见谅,其他软件不会用,求dalao推荐)

可以证明对于一个 \(N\) ,点数是 \(N - 1 + \lceil \log_2 N \rceil\)。考虑对于相同的 \(L\), 考虑 \(N\) 个叶子,至少要 \(N - 1\) 个点,而多出来的是单独一条链,也就是最后一个元素向上的链。这个链长度小于等于 \(\lceil \log_2 N \rceil\)。

所以这样子就能得到较为优秀的分数了。

然而对于每一个触发器,我们都会多一个 \(\log\)。那么为什么不放在一起呢?这样正好符合正解的复杂度。

考虑用一个统一的开关线段树维护这些触发器,然后触发器回到决策线段树的开头。

注意触发器不能回到起点,因为一个触发器可能出现多次,那么我们很难决定它是最后一个的时候怎么做。

为了回到起点,我们增加一个虚点,或者换句话说,就是往规定的触发器序列末尾加一个 \(0\)。

和上面的方法类似,我们把叶子的遍历序列存下来,同时只取在线段树右边的 \(N + 1\) 个点,根据遍历的时间来钦定触发器。

一样的,因为遍历了二的幂次,所以所有开关归零,经过开关次数 \(O\left(N \log N\right)\) 大概 \(3 \times 10^6\),也不会爆炸。

开关个数 \(O\left(N + \lceil \log_2 \left(N + 1\right) \rceil\right)\),因为judger对这个 \(\log\) 的界卡的不紧,大概可以大 \(1\),所以刚好能通过此题。

看到有些人用bitreverse,的确这样子就是bitreverse后的不断+1,可以给各种操作带来方便。

#include "doll.h"
#include <bits/stdc++.h> typedef std::vector<int> VI;
const int MAXN = 262145;
const int spe = 19260817;
int idx[MAXN], xs[MAXN], ys[MAXN];
int qli[MAXN];
int typ[MAXN], cnto[MAXN], tot, lim, N;
int tli[MAXN], t0t, cnt[MAXN];
void qry(int u, int l, int r) {
if (l == r) {
cnto[l] = ++tot;
return ;
}
int mid = l + r >> 1;
!typ[u] ? qry(u << 1, l, mid) : qry(u << 1 | 1, mid + 1, r);
typ[u] ^= 1;
}
void relable(int u, int l, int r) {
if (l == r) {
tli[++t0t] = l;
return ;
}
int mid = l + r >> 1;
relable(u << 1 | 1, mid + 1, r);
relable(u << 1, l, mid);
}
int txt;
int build(int l, int r) {
if (l == r) {
int now = cnt[l];
return now > 0 ? qli[now] : spe;
}
int mid = l + r >> 1;
int tl = build(l, mid), tr = build(mid + 1, r);
if (tl == spe && tr == spe) return spe;
int now = ++txt;
xs[now] = tl, ys[now] = tr;
return -now;
}
void create_circuit(int M, VI A) {
N = A.size(); ++N;
lim = 1;
while (lim < N) lim <<= 1;
for (int i = 1; i <= lim; ++i) qry(1, 1, lim);
relable(1, 1, lim);
std::sort(tli + 1, tli + 1 + N, [] (int a, int b) { return cnto[a] < cnto[b]; });
for (int i = 1; i <= N; ++i)
cnt[tli[i]] = i;
std::copy(A.begin(), A.end(), qli + 1);
VI C(M + 1, 0), X, Y;
int rt = build(1, lim);
for (int i = 1; i <= txt; ++i) {
xs[i] == spe ? xs[i] = rt : 0;
ys[i] == spe ? ys[i] = rt : 0;
}
for (int i = 0; i <= M; ++i) C[i] = rt;
X.assign(xs + 1, xs + 1 + txt);
Y.assign(ys + 1, ys + 1 + txt);
answer(C, X, Y);
}

【IOI2018】机械娃娃的更多相关文章

  1. [IOI2018]机械娃娃——线段树+构造

    题目链接: IOI2018doll 题目大意:有一个起点和$m$个触发器,给出一个长度为$n$的序列$a$,要求从起点出发按$a$的顺序经过触发器并回到起点(一个触发器可能被经过多次也可能不被经过), ...

  2. 【IOI 2018】Doll 机械娃娃

    我感觉这个题作为Day2T1,有一定的挑战性.为$Rxd$没有完成这道题可惜. 我觉得这道题,如果按照前几个部分分的思路来想,就有可能绕进错误的思路中.因为比如说每个传感器最多只在序列中出现$2$次, ...

  3. WC2019游记

    本来不打算写游记的,但后来想了想这么一次难忘的经历总该留下点痕迹吧...... DAY-1 走之前的最后一天,因为前一天晚上打了CF,所以早上9点才到机房.写了一道圆方树深深地体会到了来自仙人掌的恶意 ...

  4. WC2019 题目集

    最近写的一些 WC2019 上讲的一些题.还是怕忘了,写点东西记录一下. LOJ2983 「WC2019」数树 题意 本题包含三个问题: 问题 0:已知两棵 \(n\) 个节点的树的形态(两棵树的节点 ...

  5. WC 2019 游记 - 败者之低语

    败者之低语 WC 2019 游记 Day -1 看了一圈PKU和THU的题,感觉图像识别真有意思... 感觉非常讲道理,pku还是比thu简单一点的... 听说高二414在thu没有进面试? 震惊!( ...

  6. [LeetCode] Russian Doll Envelopes 俄罗斯娃娃信封

    You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envel ...

  7. 入手Invicta 8926 OB潜水自动机械腕表

    前个月前就想入手一款手表了,之前在关注和学习.询问他人选哪样的表好,前些天还在看精工Seiko机械表系列,今凌晨有朋友给我推荐这款Invicta 8926系列手表,我一看便喜欢了. 在网上也是搜索了很 ...

  8. 固态硬盘与机械硬盘 SQL Server 单表插入性能对比测试

    测试环境

  9. 机械革命 USB装系统各种坑

    买了个号称超强性价比的游戏本- 机械革命, i7+ssd+hd+4G RAM+ GTX850M, 很直接, 直接出厂就一个DOS系统,回来要自己装机. 好吧, 先下了个大白菜软件,用来刻录ISO系统到 ...

随机推荐

  1. 输出单项链表中倒数第k个结点——牛客刷题

    题目描述: 输入一个单向链表,输出该链表中倒数第k个结点 输入.输出描述: 输入说明:1.链表结点个数 2.链表结点的值3.输入k的值 输出说明:第k个结点指针 题目分析: 假设链表长度为n,倒数第k ...

  2. MySQL的简介、启动及其DDL

    MySQL的各项配置: 默认会启用TCP/IP网络: 默认客户端/服务器端口:3306: 将数据库的BIN目录写入Windows的的path环境变量: 默认不允许root用户在其他机器上远程登录: M ...

  3. 数据库HAVING的使用

    HAVING语句通常与GROUP BY语句联合使用,用来过滤由GROUP BY语句返回的记录集. HAVING语句的存在弥补了WHERE关键字不能与聚合函数联合使用的不足. 记录一下

  4. shiro学习(二)

    自定义realm(主要就是自定义的realm要继承AuthorizingRealm 类,重写两个方法(一是认证,而是授权,两个方法一般要查询数据库,这里用的是模拟数据) ) public class ...

  5. java 计算中位数方法

    最近工作需要 要求把python的代码写成java版本,python中有一个np.median()求中位数的方法,java决定手写一个 先说说什么是中位数: 中位数就是中间的那个数, 如果一个集合是奇 ...

  6. 【科创人·独家】连续创业者高春辉的这六年:高强度投入打造全球领先的IP数据库

    您能看到:高春辉的创业观,IPIP.NET半程复盘及未来规划,连续创业的体验,小众产品趣事 您看不到:往年创业的回顾,技术干货,受制于篇幅忍痛割舍的精彩观点 文末彩蛋:<与雷军的分歧并非否定电商 ...

  7. 【Git的基本操作六】分支管理

    分支管理 1. 什么是分支? 在版本控制过程中,使用对条线同时推进多个任务. 2. 分支的好处 同时并行推进多个功能开发,提高开发效率 各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任 ...

  8. ie8 下的半透明 background:rgba 与opacity失效 兼容办法

    fliter: filter: progid:DXImageTransform.Microsoft.Alpha(opacity=70);

  9. 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程

    生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...

  10. 【异常】hue:unknown database hue

    1 hue error日志报错,找不到hue数据库 2 解决办法 删除hue服务,重新添加,再次在添加database阶段验证密码,test通过,再继续. 还有造成这个事情的原因,是自己移动了mysq ...