题目链接:

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. mysql的模糊匹配

    实例: SQL模糊查询,使用like比较关键字,加上SQL里的通配符,请参考以下: 1.LIKE'Mc%' 将搜索以字母 Mc 开头的所有字符串(如 McBadden). 2.LIKE'%inger' ...

  2. PS滤镜制作下雨照片特效

    原图 一.打开你想要添加下雨效果的照片,并新建一个图层,命名为雨,填充为黑色,对“雨”层执行:滤镜 > 杂色> 添加杂色,参数如图. 二.对“雨”层执行:滤镜 > 模糊 > 高 ...

  3. MySQL 优化集锦

    case 1: 如果筛选or条件有多个的时候,应该将最好判断的放在最前面,将最不好判断的放在最后面 比如,有一个学生表,想要找出其中年龄是20岁,住址中包含666这个数字的记录.可以下面这两个方案: ...

  4. Docker bridge br0 pipework

    Docker Centos7 下建立 Docker 桥接网络 - weifengCorp - 博客园https://www.cnblogs.com/weifeng1463/p/7468497.html ...

  5. linux的nohup命令

    linux的nohup命令的用法. - runfox545 - 博客园https://www.cnblogs.com/allenblogs/archive/2011/05/19/2051136.htm ...

  6. symfony框架

    Symfony是一个完整的框架结构,设计用来帮助并加速网络应用的开发. 1)安装 symfony的安装还是比较简单的,而且提供了多种安装的方式,详情可以看官网手册 问题: cURL error 60: ...

  7. a标签中的onclick和href的使用

    onclick和href 链接的 onclick 事件被先执行,其次是 href 属性下的动作(页面跳转,或 javascript 伪链接):  假设链接中同时存在 href 与 onclick,如果 ...

  8. apache benchmark 的简单安装与测试

    1. 下载apache benchmark Copy From https://blog.csdn.net/fyqaccpt96/article/details/43272001 yum instal ...

  9. python之路--网络通信协议

    一 . osi七层协议 互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层 二 . tcp三次握手和四次挥手 我们知道网络层,可以实现两个主机之间的通信.但是这并不具体,因为,真 ...

  10. 深入python的set和dict

    一. collections中的abc 和list(Sequence)相似,都继承于Collection,添加了一些方法 二. dict的常见用法 (setdefault,defaultdict,__ ...