题目链接:

IOI2018doll

题目大意:有一个起点和$m$个触发器,给出一个长度为$n$的序列$a$,要求从起点出发按$a$的顺序经过触发器并回到起点(一个触发器可能被经过多次也可能不被经过),起点和每个触发器都有一个出口和若干个入口。你可以在这些触发器之间加上一些开关,每个开关有两个出口$x,y$和若干个入口,当奇数次进入开关时会从$x$出来,当偶数次进入开关时会从$y$出来,要求第一次回到起点时所有开关都被经过偶数次且使用的开关数尽量少,输出每个元件的出口指向。

因为最后要求回到起点,所以我们将序列$a$后面再加上一个起点。当$n=2^k$的时候可以构造一个类似线段树的满二叉树结构的装置。起点指向线段树的根,对于线段树的每个非叶字节点是一个开关,$x$出口指向左儿子,$y$出口指向右儿子;对于每个叶子节点是一个触发器(如果一个触发器在序列$a$中出现多次那么在线段树上就可以看作将它分成好几个点),他们的出口都指向线段树的根节点。这样就满足了每个非叶字节点即开关都经过了偶数次的条件。可以发现对于$a_{i}(0\le i \le n-1)$,假设它在线段树上位于第$x$个叶子,那么$i$的二进制倒序就是$x$,这个类似$FFT$的蝶形变换。所以我们只需要一次蝶形变换就能知道叶子结点的父节点左右儿子分别是谁。那么如果$n$不是$2$的整数次幂怎么办?我们同样蝶形变换将序列$a$的每一位填入线段树的叶子结点中,对于空的叶子结点就可以将这个点父节点的对应出口直接指向线段树的根节点就好了。这样我们得到了一个最坏情况下$2n$的做法,不过可以发现如果一个非叶字节点的两个出口都指向根节点那么这个开关就是无用的,可以将它删除然后将它父节点的对应出口指向根节点。这样虽然使节点数有所减少但还是达不到$n+logn$的要求。可以发现许多非叶子节点只有一个子节点,如果尽可能的使每个非叶子节点都有两个子节点那么可以节省许多的开关。实际上只要将这些放置了触发器的叶子结点按顺序地移到前$n$个叶子节点或后$n$个叶子结点即可,我们以移到前$n$个叶子结点为例说明(代码中移到了后n个叶子结点)。最后一个叶子结点从$0$开始的标号为$n-1$(除去我们在序列后面加的起点就是题目中给出的序列长度$n$),对于这个叶子结点到根的这条链,可以看做是这个节点从根走到叶子。我们将$n$拆成二进制,可以发现从左开始如果第$i$位为$0$那么在线段树的第$i$层它就会向左走,反之就会向右走。假设从右开始的第$i$位为$1$,那么这一次它就会向右走,这就说明这个点有左子树,那么节点数就会加上这个点的左子树大小即$2^i-1$,而向左走则除去这条链上的点没有其他节点数的贡献。可以发现每个有贡献的$2^i$对应了$n$二进制上的$1$,这条链上有$logn-1$个非叶子节点,所以总非叶子节点数为$O(n+logn)$。也可以将序列a的第一个数拿出来,将起点指向$a_{0}$,$a_{0}$再指向线段树的根。

#include"doll.h"
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define INF 100000000
using namespace std;
int n,m;
int rev[800010];
int mask;
int cnt;
int rt;
int s[800010];
int t[800010];
vector<int>to;
vector<int>a,c,x,y;
int solve(int l,int r)
{
if(l==r)
{
return l>=mask-n?a[t[l]]:INF;
}
int mid=(l+r)>>1;
int ls=solve(l,mid);
int rs=solve(mid+1,r);
if(ls==INF&&rs==INF)
{
return INF;
}
else
{
x.push_back(ls);
y.push_back(rs);
return --cnt;
}
}
void create_circuit(int M,vector<int> A)
{
n=A.size();
A.push_back(0);
m=M;
a=A;
mask=1;
while(mask<n)
{
mask<<=1;
}
for(int i=0;i<mask;i++)
{
rev[i]=(rev[i>>1]>>1)|((i&1)?(mask>>1):0);
s[i]=-1;
}
for(int i=mask-n;i<mask;i++)
{
s[rev[i]]=i;
}
for(int i=0;i<mask;i++)
{
if(s[i]!=-1)
{
to.push_back(s[i]);
}
}
for(int i=0;i<n;i++)
{
t[to[i]]=i+1;
}
rt=solve(0,mask-1);
c.resize(m+1,rt);
c[0]=a[0];
int len=x.size();
for(int i=0;i<len;i++)
{
x[i]==INF?x[i]=rt:1;
y[i]==INF?y[i]=rt:1;
}
answer(c,x,y);
}

[IOI2018]机械娃娃——线段树+构造的更多相关文章

  1. [IOI2018]会议——分治+线段树

    题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...

  2. Codeforces482B【线段树构造】

    题意: 有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是否有满足的数列. 思路: 看到大牛说是线段树,线段树对于区间操作,印象中乘啊,+啊,-啊都不错,但是并没有就是 ...

  3. LOJ.2864.[IOI2018]排座位(线段树)

    LOJ 洛谷 先令编号从\(1\)开始.我们要求\([1,i]\)这些数字能否构成一个矩形. 考虑能否用线段树维护,让每个叶子节点\(i\)表示前\(i\)个数能否构成矩形. 一种方法是维护前\(i\ ...

  4. [IOI2018]排座位——线段树

    题目链接: IOI2018seat 题目大意:给出一个$H*W$的矩阵,将$0 \sim W*H-1$分别填入矩阵的格子里(每个格子里一个数),定义一个子矩阵是美妙的当且仅当这个子矩阵包含且仅包含$0 ...

  5. CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理

    LINK:Phoenix and Memory 这场比赛标题好评 都是以凤凰这个单词开头的 有凤来仪吧. 其实和Hall定理关系不大. 不过这个定理有的时候会由于 先简述一下. 对于一张二分图 左边集 ...

  6. codeforces 671C Ultimate Weirdness of an Array 线段树+构造

    题解上说的很清楚了,我照着写的,表示膜拜题解 然后时间复杂度我觉得应该是O(nlogn),虽然常数略大,预处理和倒着扫,都是O(nlogn) #include <stdio.h> #inc ...

  7. 线段树(segment_tree)

    线段树之——区间修改区间查询 1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是 ...

  8. HDU1166 敌兵布阵_线段树

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  9. 线段树(Segment Tree)(转)

    原文链接:线段树(Segment Tree) 1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lg ...

随机推荐

  1. git仓库迁移

    最近,装了git的本地服务器坏掉了, 没办法只能临时进行仓库的迁移  保证项目正常进行 在项目的根目录执行右键执行 查询当前仓库的远程地址 git remote -v 查看现有远程仓库的地址url 修 ...

  2. .net core实践系列之短信服务-目录

    前言 经过两周多的业余时间,终于把该系列的文章写完了.第一次写系列,可能部分关键点并没有覆盖到,如果有疑问的朋友可以随时反馈给我.另外也感谢在我发布文章时给予我方案建议与反馈源码BUG的朋友们.下面是 ...

  3. Python之Flask笔记

    在这里先说一下最开始所经历的一些错误app=Flask(_name_),当初拼写的时候怎么都报错后来发现此处是两个'_' 配置文件 app.config.from_object(__name__) 在 ...

  4. H5 19-序选择器下

    19-序选择器下 我是项目 我是项目 我是项目 我是项目 我是项目 我是项目 我是项目 <!DOCTYPE html> <html lang="en"> & ...

  5. 深度学习之概述(Overview)

    2016年被称为人工智能的元年,2017年是人能智能应用的元年:深度学习技术和应用取得飞速发展:深度学习在互联网教育场景也得到广泛应用.本文主要介绍机器学习及深度学习之定义及基本概念.相关网络结构等. ...

  6. python中读取文件的read、readline、readlines方法区别

    #读取文件所有内容,返回字符串对象,python默认以文本方式读取文件,遇到结束符读取结束. fr = open('lenses.txt')read = fr.read()print(type(rea ...

  7. js压箱底的宝贝

    框架的确好用, 不过他们也隐藏了JavaScript中丑陋的细节和DOM的运作机制. 如果你的目标是敢于自称"我懂JavaScript", 那么花时间学习框架无异于南辕北辙. 下面 ...

  8. [转帖]SAP一句话入门:Project System

    SAP一句话入门:Project System http://blog.vsharing.com/MilesForce/A621279.html 这是SAP ERP入门的最后一篇了. 我们这些死跑龙套 ...

  9. 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》

    作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ...

  10. hive数学函数

    round 四舍五入 ceil向上 取整 floor向下取整 hive >  select floor(45.8); ok 45