[BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案)
题面
一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
强制在线。
分析
二分答案mid,表示询问的中位数在排过序的整个b序列中是第mid小.
考虑判断一个数是否<=序列的中位数:把大于等于这个数的变为1,小于它的变为-1,判断和是否大于等于0。那么就要在把mid按上述方法替换之后的序列找一个和最大的左端点在[a,b],右端点在[c,d]的子序列,
线段树维护区间最大前/后缀即可([a,b]后缀+[b,c]区间和和+[c,d]前缀).
如果能找到和>=0的子序列,那最大中位数>=b[mid],l=mid+1,否则r=mid-1
二分mid每次建显然不行,而mid-1变化到mid,只会把mid-1对应的数由1变成-1,可持久化线段树维护就行了,root[i]对应的线段树二分值为i的时候的01序列,每次查询就是查一个历史版本
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 20000
#define maxlogn 20
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
struct num{
int val;
int pos;
friend bool operator < (num p,num q){
return p.val<q.val;
}
}a[maxn+5];
struct val{
int sum;
int lmax;
int rmax;
val(){
}
val(int v){
sum=lmax=rmax=v;
}
friend val operator + (val lson,val rson){
val ans;
ans.sum=lson.sum+rson.sum;
ans.lmax=max(lson.lmax,lson.sum+rson.lmax);
ans.rmax=max(rson.rmax,rson.sum+lson.rmax);
return ans;
}
};
struct per_segment_tree{
#define lson(x) tree[x].ls
#define rson(x) tree[x].rs
struct node{
//[l,r]存储原来序列中和,最大前缀,后缀和
int ls;
int rs;
val v;
}tree[maxn*maxlogn+5];
int root[maxn+5];
int ptr;
void push_up(int x){
tree[x].v=tree[lson(x)].v+tree[rson(x)].v;
}
void build(int &x,int l,int r){
x=++ptr;
if(l==r){
tree[x].v=val(1);
return;
}
int mid=(l+r)>>1;
build(tree[x].ls,l,mid);
build(tree[x].rs,mid+1,r);
push_up(x);
}
void insert(int &x,int last,int upos,int v,int l,int r){
x=++ptr;
tree[x]=tree[last];
if(l==r){
tree[x].v=val(v);
return;
}
int mid=(l+r)>>1;
if(upos<=mid) insert(tree[x].ls,tree[last].ls,upos,v,l,mid);
else insert(tree[x].rs,tree[last].rs,upos,v,mid+1,r);
push_up(x);
}
val query(int x,int L,int R,int l,int r){
if(L>R){
return val(0);
}
if(L<=l&&R>=r){
return tree[x].v;
}
int mid=(l+r)>>1;
// val ans;
if(L<=mid&&R>mid){
return query(tree[x].ls,L,R,l,mid)+query(tree[x].rs,L,R,mid+1,r);
}else if(L<=mid){
return query(tree[x].ls,L,R,l,mid);
}else if(R>mid){
return query(tree[x].rs,L,R,mid+1,r);
}
return val(0);
}
#undef lson
#undef rson
}T;
int check(int l1,int r1,int l2,int r2,int mid){
int sum=T.query(T.root[mid],l1,r1,1,n).rmax+T.query(T.root[mid],r1+1,l2-1,1,n).sum+T.query(T.root[mid],l2,r2,1,n).lmax;
if(sum>=0) return 1;
else return 0;
}
int bin_search(int l1,int r1,int l2,int r2){
int l=1,r=n;
int mid;
int ans;
while(l<=r){
mid=(l+r)>>1;
if(check(l1,r1,l2,r2,mid)){
ans=mid;
l=mid+1;
}else r=mid-1;
}
return ans;
}
int q[4];
int main(){
int last=0,ans=0;
int l1,r1,l2,r2;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].val);
a[i].pos=i;
}
sort(a+1,a+1+n);//我们二分的是中位数是排序后的第几个,所以要sort
T.build(T.root[1],1,n);//一开始,所有数都大于b[mid],都为1
for(int i=2;i<=n;i++){
T.insert(T.root[i],T.root[i-1],a[i-1].pos,-1,1,n);//预处理mid=i时的线段树
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d %d %d %d",&l1,&r1,&l2,&r2);
q[0]=(l1+last)%n;
q[1]=(r1+last)%n;
q[2]=(l2+last)%n;
q[3]=(r2+last)%n;
sort(q,q+4);
ans=a[bin_search(q[0]+1,q[1]+1,q[2]+1,q[3]+1)].val;
printf("%d\n",ans);
last=ans;
}
}
[BZOJ 2653] middle(可持久化线段树+二分答案)的更多相关文章
- BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)
题意: 左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值 思路: 对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1 ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- 【BZOJ-2653】middle 可持久化线段树 + 二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1298 Solved: 734[Submit][Status][Discu ...
- BZOJ 4552 [Tjoi2016&Heoi2016]排序 ——线段树 二分答案
听说是BC原题. 好题,二分答案变成01序列,就可以方便的用线段树维护了. 然后就是区间查询和覆盖了. #include <map> #include <cmath> #inc ...
- 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块
!!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...
- 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)
有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...
- 【bzoj2653】middle 可持久化线段树区间合并
题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...
- 【Codechef FRBSUM】【FJOI2016】【BZOJ4299】【BZOJ 4408】 可持久化线段树
4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 475 Solved: 287[Submit][Status ...
- BZOJ - 3123 森林 (可持久化线段树+启发式合并)
题目链接 先把初始边建成一个森林,每棵树选一个根节点递归建可持久化线段树.当添加新边的时候,把结点数少的树暴力重构,以和它连边的那个点作为父节点继承线段树,并求出倍增数组.树的结点数可以用并查集来维护 ...
随机推荐
- pg_dumpall - 抽出一个 PostgreSQL 数据库集群到脚本文件中
SYNOPSIS pg_dumpall [ option...] DESCRIPTION 描述 pg_dumpall 是一个用于写出("转储")一个数据库集群里的所有 Postgr ...
- VPS建站
参考腾讯云的教程 选择了 LAMP的方案,即Linux + Apache + MySQL + Php 参考链接 https://cloud.tencent.com/edu/learning/cours ...
- bzoj4940 [Ynoi2016]这是我自己的发明 莫队+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4940 题解 对于换根操作,处理方法就很套路了. 首先先假定以 \(1\) 为根做一遍 dfs, ...
- django之模型类在视图中的应用
一:模型类直接从把前端表单传入的值,进行存储. @csrf_exempt def regist(request): if request.method == 'POST': form = UserFo ...
- LINUX的一些基本概念和操作
LINUX和shell的关系: linux是核,是操作系统,用于分配软硬件资源,用于支持运行环境,shell是壳,是命令解析器. linux命令: linux命令行有一个输入输出的行为,输入命令,输出 ...
- maven编译问题之 -The POM for XXX is invalid, transitive dependencies (if any) will not be available
问题一: 把父工程tao-parent install 到maven本地仓后,接着install tao-common工程,然后报错 报错信息如下: [WARNING] The POM for com ...
- linux运维、架构之路-linux磁盘管理
一.企业中磁盘选购: 1.线上的业务,用SAS磁盘 2.线下的业务,用SATA磁盘,磁带库 3.线上高并发.小容量(多人浏览力图片)的业务,SSD磁盘 4.根据数据的访问热度,智能分析分层存储,SAT ...
- 从保障淘宝到全球市场“第一阵营”,阿里云的DDoS防护之路走了多远?
2年前,不少技术圈的朋友,读过论坛里的一篇解读文章:DDoS,阿里为什么要走自己的一条路(https://bbs.aliyun.com/read/271764.html?pos=13),文章讲述了阿里 ...
- mysql中各种连接的区别
现在有如下两个表: A表. B表. 一:使用笛卡尔连接 SELECT * FROM a,b 结果: 二:内连接 SELECT * FROM a INNER JOIN b on a.a_id=b.par ...
- Page.after
解释: Page.after可以增加Page级的切面,触发的时机是在所拦截的对应生命周期方法执行之后,也可以拦截所有页面上发生的事件(对于要拦截的事件,在swan文件上必须显示绑定了相应事件). 方法 ...