题目链接:

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 config --global user.name "kszsa" git config --global user.email "duyon ...

  2. docker容器与宿主交互数据

    1.查看容器 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cd6957191 ...

  3. python之面向对象3

     面向对象介绍 一.面向对象和面向过程 面向过程:核心过程二字,过程即解决问题的步骤,就是先干什么后干什么 基于该思想写程序就好比在这是一条流水线,是一种机械式的思维方式 优点:复杂的过程流程化 缺点 ...

  4. Python-类的绑定方法与非绑定方法

    类中定义的函数分成两大类 一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 类.boud_method() ...

  5. Yii1.1框架实现PHP极光推送消息通知

    一.下载极光推送PHP SDK,解压后放在/protected/components/目录下,如下图所示: 二.完善修改下官方的demo例子,我这里复制一份demo,改为NotifyPush.php, ...

  6. 软件扒网站? 爬虫? F12查看源码? 查看网页源代码?浏览器sources? 区别和联系!

    1.软件扒网站: 利用各类扒站网站,如仿站小工具8.0,可以按照规则将网站的未经浏览器简析的前端代码扒下来,并整理成css,js,html等文件夹,很方便.(当然看不到ajax等相关代码) 备注:如果 ...

  7. openstack-虚拟化模型

    一. 虚拟化模型 1.虚拟化模型 图1 虚拟化模型 图2 KVM架构 2.KVM模块 处理器虚化 内存虚化 3.QEMU设备模型 其它虚化(网卡.声卡.显卡等)

  8. charles如何设置弱网

  9. 敏捷开发、DevOps相关书籍——书单

    自己瞎整理的一些书单,都是豆瓣评分比较高的书,可以作为选择的一个参考. 书名 豆瓣链接 持续交付:发布可靠软件的系统方法 https://book.douban.com/subject/6862062 ...

  10. vscode开发中绝对让你惊艳的插件!!!(个人在用)

    识别模版引擎 1.Apache Velocity :识别Velocity(vm) 2.Art Template Helper:识别artTemplate 点击路径跳转 1.Laravel goto v ...