2653: middle

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 2522  Solved: 1434
[Submit][Status][Discuss]

Description

一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

Input

第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
输入保证满足条件。
第一行所谓“排过序”指的是从小到大排序!
n<=20000,Q<=25000
 

Output

Q行依次给出询问的答案。

Sample Input

5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0

Sample Output

271451044
271451044
969056313

HINT

 

Source

思路:

这道题比较容易想到二分答案,但是check答案比较难想

我们考虑check某个数的时候把大于它的值设为1,小于它的设为-1,那么对【b+1,c-1】区间取和,对【a,b】取右端最大,对【c,d】取左端最大加来如果大于等于0,那么说明值在右边,往右边二分否则往左边二分,

但是如果我们每次check重新建一遍线段树,那肯定是会超时的,我们用主席树存就好了,我们先将主席树上各个点的值赋为1,然后依次输入2-n,每次输入将前一个数赋值为-1(因为排完序后前一个数一定比当前数小),那么当 root [k] 时主席树上的值就等于之前对k建的线段树,主席树上我们维护三个值,一个是区间和,一个是右端最大,以及左端最大。

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define mid int m = (l + r) >> 1
const int M = 2e4 + ;
int sum[M*],lsum[M*],rsum[M*],ls[M*],rs[M*],root[M],b[];
int idx,n;
struct node{
int val,id;
}a[M]; bool cmp(node x,node y){
return x.val < y.val;
} void pushup(int rt){
sum[rt] = sum[ls[rt]] + sum[rs[rt]];
lsum[rt] = max(lsum[ls[rt]],sum[ls[rt]]+lsum[rs[rt]]);
rsum[rt] = max(rsum[rs[rt]],sum[rs[rt]]+rsum[ls[rt]]);
} void build(int l,int r,int &rt){
rt = ++idx;
if(l == r){
sum[rt] = lsum[rt] = rsum[rt] = ;
return ;
}
mid;
build(l,m,ls[rt]); build(m+,r,rs[rt]);
pushup(rt);
} void update(int p,int l,int r,int old,int &rt){
rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old];
if(l == r){
sum[rt] = lsum[rt] = rsum[rt] = -;
return ;
}
mid;
if(p <= m) update(p,l,m,ls[old],ls[rt]);
else update(p,m+,r,rs[old],rs[rt]);
pushup(rt);
} int query_sum(int L,int R,int l,int r,int rt){
if(L <= l&&R >= r){
return sum[rt];
}
mid;
int ret = ;
if(L <= m) ret += query_sum(L,R,l,m,ls[rt]);
if(R > m) ret += query_sum(L,R,m+,r,rs[rt]);
return ret;
} int query_lsum(int L,int R,int l,int r,int rt){
if(L <= l&&R >= r){
return lsum[rt];
}
mid;
if(R <= m) return query_lsum(L,R,l,m,ls[rt]);
else if(L > m) return query_lsum(L,R,m+,r,rs[rt]);
else return max(query_lsum(L,R,l,m,ls[rt]),query_sum(L,R,l,m,ls[rt])+query_lsum(L,R,m+,r,rs[rt]));
} int query_rsum(int L,int R,int l,int r,int rt){
if(L <= l&&R >= r){
return rsum[rt];
}
mid;
if(R <= m) return query_rsum(L,R,l,m,ls[rt]);
else if(L > m) return query_rsum(L,R,m+,r,rs[rt]);
else return max(query_rsum(L,R,m+,r,rs[rt]),query_sum(L,R,m+,r,rs[rt])+query_rsum(L,R,l,m,ls[rt]));
} bool check(int a,int b,int c,int d,int rt){
int cnt = ;
if(c- > b) cnt += query_sum(b+,c-,,n,root[rt]);
cnt += query_rsum(a,b,,n,root[rt]);
cnt += query_lsum(c,d,,n,root[rt]);
return cnt >= ;
} int main()
{
scanf("%d",&n);
for(int i = ;i <= n;i ++){
scanf("%d",&a[i].val);
a[i].id = i;
}
sort(a+,a++n,cmp);
build(,n,root[]);
for(int i = ;i <= n;i ++)
update(a[i-].id,,n,root[i-],root[i]);
int q,last = ;
scanf("%d",&q);
for(int i = ;i <= q;i ++){
scanf("%d%d%d%d",&b[],&b[],&b[],&b[]);
for(int j = ;j <= ;j ++)
b[j] = (b[j]+last)%n;
sort(b+,b+);
b[]++; b[]++; b[]++; b[]++;
int l = ,r = n,k;
while(l <= r){
mid;
if(check(b[],b[],b[],b[],m))
k = m,l = m+;
else r = m - ;
}
last = a[k].val;
printf("%d\n",last);
}
}

bzoj 2653: middle (主席树+二分)的更多相关文章

  1. BZOJ 2653: middle(主席树+二分答案)

    传送门 解题思路 首先可以想到一种暴力做法,就是询问时二分,然后大于等于这个值的设为1,否则设为-1,然后就和GSS1那样统计答案.但是发现这样时间空间复杂度都很爆炸,所以考虑预处理,可以用主席树来做 ...

  2. BZOJ 2653: middle 主席树 二分

    https://www.lydsy.com/JudgeOnline/problem.php?id=2653 因为是两个方向向外延伸所以不能对编号取前缀和(这里只有前缀和向后传递的性质,不是实际意义的和 ...

  3. bzoj 2653 middle(主席树)

    题面:https://vjudge.net/problem/HYSBZ-2653 博客:https://blog.csdn.net/litble/article/details/78984846 这个 ...

  4. BZOJ 2653: middle [主席树 中位数]

    传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右 ...

  5. BZOJ 2653 middle | 主席树

    题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2653 题解: 设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前an ...

  6. [BZOJ2653]middle 主席树+二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2042  Solved: 1123[Submit][Status][Disc ...

  7. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  8. BZOJ.1926.[SDOI2010]粟粟的书架(前缀和 主席树 二分)

    题目链接 题意: 在给定矩形区域内找出最少的数,满足和>=k.输出数的个数.两种数据范围. 0~50 注意到(真没注意到...)P[i,j]<=1000,我们可以利用前缀和预处理. num ...

  9. 2018湘潭邀请赛C题(主席树+二分)

    题目地址:https://www.icpc.camp/contests/6CP5W4knRaIRgU 比赛的时候知道这题是用主席树+二分,可是当时没有学主席树,就连有模板都不敢套,因为代码实在是太长了 ...

随机推荐

  1. make太慢了,加快编译速度的方法 make -j

    make -j 既然IO不是瓶颈,那CPU就应该是一个影响编译速度的重要因素了. 用make -j带一个参数,可以把项目在进行并行编译,比如在一台双核的机器上,完全可以用make -j4,让make最 ...

  2. Python_迭代器_35

    迭代器 # l = [1,2,3]# 索引# 循环 for# for i in l:# i## for k in dic:# pass #可以被for循环的# list# dic# str# set# ...

  3. python学习之第八篇——字典嵌套之字典中嵌套字典

    cities = { 'shanghai':{'country':'china','population':10000,'fact':'good'}, 'lendon':{'country':'eng ...

  4. Python“Non-ASCII character 'xe5' in file”报错问题

    今天在编译一个Python程序的时候,一直出现“Non-ASCII character 'xe5' in file”报错问题 SyntaxError: Non-ASCII character '\xe ...

  5. [2017BUAA软工助教]个人项目小结

    2017BUAA个人项目小结 一.作业链接 http://www.cnblogs.com/jiel/p/7545780.html 二.评分细则 0.注意事项 按时间完成并提交--正常评分 晚交一周以内 ...

  6. 如何让pl/sql developer记住密码,实现快速登录

    前两天,有同事使用plsql的时候,切换数据库的时候需要不断的重复输入密码,这样太麻烦了. 下面,我这里说下如何的实现plsql不需要输入密码就能快速登录的方法: 1.一开始登录,首先像往常那样输入密 ...

  7. zTree树形菜单使用实例

    在每个节点添加 id 和 pid, id 表示当前节点编号,pid 表示父节点编号 第一步:在页面显示菜单位置,添加 ul设置 class=”ztree” 第二步:开启简单数据格式支持 第三步:编写树 ...

  8. CSS硬件加速的好与坏

    本文翻译自Ariya Hidayat的Hardware Accelerated CSS: The Nice vs The Naughty.感谢Kyle He帮助校对. 每个人都痴迷于60桢每秒的顺滑动 ...

  9. keras中TimeDistributed的用法

    TimeDistributed这个层还是比较难理解的.事实上通过这个层我们可以实现从二维像三维的过渡,甚至通过这个层的包装,我们可以实现图像分类视频分类的转化. 考虑一批32个样本,其中每个样本是一个 ...

  10. class面向对象-1

    一.基本定义 class cl(object): def __init(self,var) self.var=var def func(self,i) print('%s is in %s'%(i,s ...