[IOI2018]机械娃娃——线段树+构造
题目链接:
题目大意:有一个起点和$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]机械娃娃——线段树+构造的更多相关文章
- [IOI2018]会议——分治+线段树
题目链接: [IOI2018]meetings 题目大意:有$n$座山峰,每座山峰有一个高度,有$q$次询问,每次需要确定一个开会山峰使$[l,r]$所有山峰上的人都前往开会山峰,一个山峰的人去开会的 ...
- Codeforces482B【线段树构造】
题意: 有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是否有满足的数列. 思路: 看到大牛说是线段树,线段树对于区间操作,印象中乘啊,+啊,-啊都不错,但是并没有就是 ...
- LOJ.2864.[IOI2018]排座位(线段树)
LOJ 洛谷 先令编号从\(1\)开始.我们要求\([1,i]\)这些数字能否构成一个矩形. 考虑能否用线段树维护,让每个叶子节点\(i\)表示前\(i\)个数能否构成矩形. 一种方法是维护前\(i\ ...
- [IOI2018]排座位——线段树
题目链接: IOI2018seat 题目大意:给出一个$H*W$的矩阵,将$0 \sim W*H-1$分别填入矩阵的格子里(每个格子里一个数),定义一个子矩阵是美妙的当且仅当这个子矩阵包含且仅包含$0 ...
- CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理
LINK:Phoenix and Memory 这场比赛标题好评 都是以凤凰这个单词开头的 有凤来仪吧. 其实和Hall定理关系不大. 不过这个定理有的时候会由于 先简述一下. 对于一张二分图 左边集 ...
- codeforces 671C Ultimate Weirdness of an Array 线段树+构造
题解上说的很清楚了,我照着写的,表示膜拜题解 然后时间复杂度我觉得应该是O(nlogn),虽然常数略大,预处理和倒着扫,都是O(nlogn) #include <stdio.h> #inc ...
- 线段树(segment_tree)
线段树之——区间修改区间查询 1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是 ...
- HDU1166 敌兵布阵_线段树
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- 线段树(Segment Tree)(转)
原文链接:线段树(Segment Tree) 1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lg ...
随机推荐
- CentOS 7 源码编译安装 Redis
1.下载源码并解压 wget http://download.redis.io/releases/redis-4.0.10.tar.gz tar -xzf redis-4.0.10.tar.gz cd ...
- C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 客户端多网络支持
客户端可以支持灵活的,中间层连接选择,由于我们系统的定位架构大型信息系统的,所以全国各地,甚至国外的用户也会有,所以需要支持全网络配置,只要配置了中间层,可以选择连接哪个中间层的服务程序.客户端可以进 ...
- SAI窗口无法移动
昨天开SAI遇到了一个很奇怪的问题,改变了双屏的位置后SAI的窗口不能移动两边也有黑边,貌似是这样,标题栏只能进行上下改变窗口大小,不能移动窗体 问题是这样出现的:把任务栏解除锁定拖到侧边就会这样 解 ...
- H5 文字属性
03-文字属性 我是文字 我是文字 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <me ...
- new、getInstance()、newInstance()、Class.forName()
1.对象使用之前通过getinstance()得到而不需要自己定义,用完之后不需要delete: 2.new 一定要生成一个新对象,分配内存:getInstance() 则不一定要再次创建,它可以把一 ...
- Linux—CentOS7下python开发环境配置
CentOS7下python开发环境配置 上一篇博客讲了如何在Centos7下安装python3(https://www.cnblogs.com/zivli/p/9937608.html),这一次配置 ...
- PS 十分钟教你做出文字穿插效果
- CodeForces Round #548 Div2
http://codeforces.com/contest/1139 A. Even Substrings You are given a string s=s1s2…sns=s1s2…sn of l ...
- WCF使用相关
1.不显示WCF服务主机 在WCF项目属性中的WCF选项卡总关闭下图的选项 2.在其他项目中承载WCF服务 其他加载的操作一致,需要把WCF的endpoint和behavior节点复制到 启动服务的那 ...
- sys模块进度条玩法笔记
#! /user/bin/env python# -*- encoding:utf-8 -*-import time,sys for i in range(31): sys.stdout.write( ...