BZOJ 4408 FJOI2016 神秘数 可持久化线段树
Description
一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
1 = 1
2 = 1+1
3 = 1+1+1
4 = 4
5 = 4+1
6 = 4+1+1
7 = 4+1+1+1
8无法表示为集合S的子集的和,故集合S的神秘数为8。
现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。
Input
第一行一个整数n,表示数字个数。
第二行n个整数,从1编号。
第三行一个整数m,表示询问个数。
以下m行,每行一对整数l,r,表示一个询问。
Output
对于每个询问,输出一行对应的答案。
Sample Input
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5
Sample Output
4
8
8
8
HINT
对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9
题意极为简洁。。。。
可以发现这个题需要分析一些性质来判断一个数是否可以被凑出来。一个数被凑出来的时候一定不会用到大于它的数字,只可能会用到小于它的数字。
问题看起来很无序,那么找到一个考虑的顺序,把询问区间内所有的数字从小到大开始考虑。首先看有没有1,如果有,那么1就可以凑出来,同时可以发现如果有x个1,那么1~x都可以凑出来。那么考虑1~x范围内的所有数字,你可发现任何一个非1的数字都可以使我们可以连续表达的数字区间增大了(脑补一个移动的窗口),1~x区间内能表示出的最大数字就是 x+(区间内小于等于x的最大值)。仔细一想这正是一个同构子问题!
每一次都这样做,我们最多会扩大几次考虑范围呢?不难发现只要还有答案成立,这一次扩大之后的考虑范围至少是上一次的两倍,所以最多也就log级别。
于是我们只需要维护区间内小于等于某个数字的和就可以了,开心上一发主席树板子。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int MAXN=; int N,M,AA[MAXN],rank[MAXN],tot;
struct persistable_segment_tree{
static const int maxn=;
static const int maxm=;
int root[maxm],np,lc[maxn],rc[maxn],sum[maxn];
persistable_segment_tree(){ np=; }
void pushup(int now){ sum[now]=sum[lc[now]]+sum[rc[now]]; }
void build(int &now,int L,int R){
now=++np,lc[now]=rc[now]=sum[now]=;
if(L==R) return;
int m=L+R>>;
build(lc[now],L,m); build(rc[now],m+,R);
}
int copynode(int now){
np++,lc[np]=lc[now],rc[np]=rc[now],sum[np]=sum[now];
return np;
}
void update(int &now,int L,int R,int pos,int v){
now=copynode(now);
if(L==R){ sum[now]+=v; return; }
int m=L+R>>;
if(pos<=m) update(lc[now],L,m,pos,v);
else update(rc[now],m+,R,pos,v);
pushup(now);
}
int query(int xx,int yy,int L,int R,int A,int B){
if(A<=L&&R<=B) return sum[yy]-sum[xx];
int m=L+R>>;
if(B<=m) return query(lc[xx],lc[yy],L,m,A,B);
if(A>m) return query(rc[xx],rc[yy],m+,R,A,B);
return query(lc[xx],lc[yy],L,m,A,B)+query(rc[xx],rc[yy],m+,R,A,B);
}
}st; void data_in()
{
scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d",&AA[i]);
scanf("%d",&M);
}
void work()
{
memcpy(rank,AA,sizeof(AA));
sort(rank+,rank+N+);
tot=unique(rank+,rank+N+)-rank;
st.build(st.root[],,tot-);
for(int i=;i<=N;i++){
st.root[i]=st.root[i-];
st.update(st.root[i],,tot-,lower_bound(rank+,rank+tot,AA[i])-rank,AA[i]);
}
int l,r,pos,ans,tmp;
for(int i=;i<=M;i++){
scanf("%d%d",&l,&r);
pos=upper_bound(rank+,rank+tot,)-rank-,ans=;
while(pos){
tmp=st.query(st.root[l-],st.root[r],,tot-,,pos);
if(tmp<ans) break;
ans=tmp+;
if(pos==tot-) break;
pos=upper_bound(rank+,rank+tot,ans)-rank-;
}
printf("%d\n",ans);
}
}
int main()
{
data_in();
work();
return ;
}
BZOJ 4408 FJOI2016 神秘数 可持久化线段树的更多相关文章
- (bzoj4408)[FJOI2016]神秘数(可持久化线段树)
(bzoj4408)[FJOI2016]神秘数(可持久化线段树) bzoj luogu 对于一个区间的数,排序之后从左到右每一个数扫 如果扫到某个数a时已经证明了前面的数能表示[1,x],那么分情况: ...
- Bzoj 4408: [Fjoi 2016]神秘数 可持久化线段树,神题
4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 177 Solved: 128[Submit][Status ...
- BZOJ 4408: [Fjoi 2016]神秘数 可持久化线段树
4408: [Fjoi 2016]神秘数 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4408 Description 一个可重复数字集 ...
- 【BZOJ-4408】神秘数 可持久化线段树
4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 475 Solved: 287[Submit][Status ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- 51Nod 1175 区间中第K大的数 (可持久化线段树+离散)
1175 区间中第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 一个长度为N的整数序列,编号0 - N - 1.进行Q次查询,查询编号i至j的所有 ...
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
随机推荐
- JavaScript函数-高阶函数
JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数. function add(x,y,f) ...
- 如何用Redlock实现分布式锁
转载请标明出处: http://blog.csdn.net/forezp/article/details/70305336 本文出自方志朋的博客 之前写过一篇文章<如何在springcloud分 ...
- 菜鸟笔记 -- Chapter 1 计算机从0到1
进入20世纪第二个十年,计算机已经成为生活中一个必不可小的工具了,但我们真的了解计算机吗?计算机有哪些部分构成?不同的计算机又可以做什么样的事情呢?我们的PC和用来做加减乘除的计算器都属于计算机范畴吗 ...
- 一位90后程序员的自述:如何从年薪3w到30w
▌自我介绍 引用赵真老师的一首歌<过去不是错>中的一句话:过去不是过错,毕竟我们也开心过.过去不是过错,何必愧疚不知所措. 我们这一代人,我相信多少都会有人和我一样,坚持过一个游戏,叫 D ...
- 洛谷P3871 [TJOI2010]中位数(splay)
题目描述 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将一个序列按照从 ...
- WebMagic 启动例子报错
报错内容: Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/conn/Http ...
- 揭开js之constructor属性的神秘面纱
揭开 constructor 在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中.这个 ...
- 神级编辑器 sublime text 和 神级插件 emmet
h1{foo}和a[href=#] 生成如下代码 <h1>foo</h1> <a href="#"></a> 嵌套的使用 > ...
- ctf题目writeup(8)
2019.2.11 南京邮电的ctf平台: 地址http://ctf.nuptzj.cn/challenges# 他们好像搭新的平台了...我注册弄了好半天... 1. 签到题,打开网址: 查看一下页 ...
- linux文件操作篇 (一)文件属性与权限
文件的属性和权限是linux中 目录 和 文件 的两个基本特性. #属性: . 所有者属性 . 访问权限属性 -rwxrwxr-x #第一个字符是文件类别 -表示 普通文件 d 表示目录 b 表示 ...