BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负。
对于询问\((a,b,c,d)\),同样也可以二分中位数\(x\),然后把原序列对应地改为\(+1\)或\(-1\)。
此时区间\([b,c]\)中的数是必选的,求一个和\(sum\)。显然对于区间\([a,b-1]\),我们可以求一个和最大的后缀;对于区间\([c+1,d]\),可以求一个和最大的前缀。然后判断总和是否非负。
这些都可以建出线段树来维护。
显然每次二分不能重新建树。考虑刚开始时对每个\(x\)建一棵树。
假设序列中的数互不相同,每次二分的数从\(x\)变成\(x+1\)时,显然与\(x\)相比,从\(+1\)变成\(-1\)的数只有一个。也就是每次与上一次相比,只会改变一个位置。
如果序列中的数会重复,显然总复杂度也不会受影响。
所以可以对每个\(x\)建可持久化线段树,维护区间和、最大前缀后缀和即可。
复杂度\(O(n\log n+q\log^2n)\)。
对于重复的数(假设有\(c\)个位置满足\(A_i=x\)),其实不需要去重,建\(c\)棵不同的线段树即可。无论真正的中位数和\(x\)的关系如何,一定能二分到正确位置。
如果去重,注意对于每个值我们要保留最开始的那棵树(比如2 2 2,一直修改root[now]的话会是-1 -1 1,实际上可以是1 1 1 )。注意线段树范围是1~n不是1~cnt。。
去重虽然能优化二分边界,但是好像没什么实际效果(更慢了)= =
话说这就是可持久化线段树啊,为什么要叫它主席树呢
//12848kb 756ms
#include <cstdio>
#include <cctype>
#include <assert.h>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 50000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=20005;
int root[N];
std::pair<int,int> A[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Segment_Tree
{
#define ls son[x][0]
#define rs son[x][1]
#define S N*19//建树还有一个2n空间,但是不要卡着开n(2+logn)= =
int tot,Ans,son[S][2],sum[S],pre[S],suf[S];
#undef S
inline void Update(int x)
{
int l=ls, r=rs;
sum[x]=sum[l]+sum[r];
pre[x]=std::max(pre[l],sum[l]+pre[r]);
suf[x]=std::max(suf[r],sum[r]+suf[l]);
}
void Build(int &x,int l,int r)
{
x=++tot;
if(l==r) {sum[x]=pre[x]=suf[x]=1; return;}
int m=l+r>>1;
Build(ls,l,m), Build(rs,m+1,r), Update(x);
}
void Modify(int &x,int y,int l,int r,int p)
{
x=++tot;
if(l==r) {sum[x]=-1; return;}
int m=l+r>>1;
p<=m ? (rs=son[y][1],Modify(ls,son[y][0],l,m,p)) : (ls=son[y][0],Modify(rs,son[y][1],m+1,r,p));
Update(x);
}
int QuerySum(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R) return sum[x];
int m=l+r>>1;
if(L<=m)
if(m<R) return QuerySum(ls,l,m,L,R)+QuerySum(rs,m+1,r,L,R);
else return QuerySum(ls,l,m,L,R);
return QuerySum(rs,m+1,r,L,R);
}
void QueryPre(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
Ans=std::max(pre[x],Ans+sum[x]);
return;
}
int m=l+r>>1;
if(m<R) QueryPre(rs,m+1,r,L,R);
if(L<=m) QueryPre(ls,l,m,L,R);//max(QueryPre(lson),QuerySum(lson)+QueryPre(rson)) 这样写的复杂度是啥啊...= =
}
void QuerySuf(int x,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
Ans=std::max(suf[x],Ans+sum[x]);
return;
}
int m=l+r>>1;
if(L<=m) QuerySuf(ls,l,m,L,R);
if(m<R) QuerySuf(rs,m+1,r,L,R);
}
}T;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-48,c=gc());
return now;
}
bool Check(int x,int n,int a,int b,int c,int d)
{
int s=T.QuerySum(root[x],1,n,b,c);
if(s>=0) return 1;
if(a<b)
{
T.Ans=0, T.QuerySuf(root[x],1,n,a,b-1);//可以用同一个函数直接Query合并区间的=v= 为了常数算了= =
if((s+=T.Ans)>=0) return 1;
}
if(c<d)
{
T.Ans=0, T.QueryPre(root[x],1,n,c+1,d);
if((s+=T.Ans)>=0) return 1;
}
return 0;
}
int main()
{
static int ref[N];
const int n=read();
for(int i=1; i<=n; ++i) A[i]=std::make_pair(read(),i);
std::sort(A+1,A+1+n); int cnt=1; ref[1]=A[1].first;
for(int i=2; i<=n; ++i) if(A[i].first!=A[i-1].first) ref[++cnt]=A[i].first;
T.Build(root[1],1,n), root[2]=root[1];
// for(int i=2; i<=n; ++i) T.Modify(root[i],root[i-1],1,n,A[i-1].second);
for(int i=2,now=2; i<=n; ++i)//A[n]不用管.
{
T.Modify(root[now],root[now],1,n,A[i-1].second);
if(A[i].first!=A[i-1].first) ++now, root[now]=root[now-1];//root[++now]=root[now-1] 还是不要写这种语句了=-=
}
for(int Q=read(),ans=0,q[4]; Q--; )
{
q[0]=(read()+ans)%n+1, q[1]=(read()+ans)%n+1, q[2]=(read()+ans)%n+1, q[3]=(read()+ans)%n+1;
std::sort(q,q+4);
int l=1,r=cnt,mid;
while(l<=r)
if(Check(mid=l+r>>1,n,q[0],q[1],q[2],q[3])) ans=mid, l=mid+1;
else r=mid-1;
printf("%d\n",ans=ref[ans]);
}
return 0;
}
BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)的更多相关文章
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- 【BZOJ-2653】middle 可持久化线段树 + 二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1298 Solved: 734[Submit][Status][Discu ...
- [bzoj 2653][国家集训队]middle
传送门 Description 一个长度为\(n\)的序列\(a\),设其排过序之后为\(b\),其中位数定义为\(b[n/2]\),其中\(a,b\)从\(0\)开始标号,除法取下整. 给你一个长度 ...
- [BZOJ 3123] [SDOI 2013]森林(可持久化线段树+并查集+启发式合并)
[BZOJ 3123] [SDOI 2013]森林(可持久化线段树+启发式合并) 题面 给出一个n个节点m条边的森林,每个节点都有一个权值.有两种操作: Q x y k查询点x到点y路径上所有的权值中 ...
- BZOJ 2653 middle (可持久化线段树+中位数+线段树维护最大子序和)
题意: 左端点在[a,b],右端点在[c,d],求这个线段里中位数(上取整)最大值 思路: 对数组离散化,对每一个值建中位数的可持久化线段树(有重复也没事),就是对于root[i],大于等于i的值为1 ...
- BZOJ 3653: 谈笑风生(DFS序+可持久化线段树)
首先嘛,还是太弱了,想了好久QAQ 然后,这道题么,明显就是求sigma(size[x]) (x是y的儿子且层树小于k) 然后就可以发现:把前n个节点按深度建可持久化线段树,就能用前缀和维护了 其实不 ...
- 【bzoj2653】middle 可持久化线段树区间合并
题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
- bzoj 3514: GERALD07加强版 lct+可持久化线段树
题目大意: N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解: 这道题考试的时候没想出来 于是便爆炸了 结果今天下午拿出昨天准备的题表准备做题的时候 题表里就有这题 ...
随机推荐
- 论文阅读笔记十四:Decoupled Deep Neural Network for Semi-supervised Semantic Segmentation(CVPR2015)
论文链接:https://arxiv.org/abs/1506.04924 摘要 该文提出了基于混合标签的半监督分割网络.与当前基于区域分类的单任务的分割方法不同,Decoupled 网络将分割与分类 ...
- windows客户端走代理上网
前提:在大型网络中,由于众多服务器及安全性考虑,内网服务器是不能上外网的,但是为了满足某些服务的需要,一定会搭建代理服务器的. 以下是windows客户端走代理服务器的操作: 两下确定就可 ...
- 20165206 2017-2018-2 《Java程序设计》第9周学习总结
20165206 2017-2018-2 <Java程序设计>第9周学习总结 教材学习内容总结 URL类:URL类是java.net包中的一个重要的类,使用URL创建对象的应用程序称为客户 ...
- 磁盘修改AF
请严格按照如下流程: 1 以管理员打开 硬盘安装助手 2 选择苹果Mac系统镜像 (cdr格式的) 3 直接选择要写入的盘,不要点击右边的方框中的勾选 (此时就可以写入了,虽然最后还是显示 Chang ...
- 有道词典Linux版下载安装
http://cidian.youdao.com/index-linux.html Ubuntu http://codown.youdao.com/cidian/linux/youdao-dict_1 ...
- 解开一个疑惑,为什么LVS开放的端口,使用netstat或ss命令,不能查找到其监听的端口呢?
RT, 这个疑问,本周一直在心里,今天找到一个说法. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 另外LVS规则算是内核方法,用netstat -ntulp也显 ...
- Zookeeper(一)CentOS7.5搭建Zookeeper3.4.12集群与命令行操作
一. 分布式安装部署 1.0 下载地址 官网首页: https://zookeeper.apache.org/ 下载地址: http://mirror.bit.edu.cn/apache/zookee ...
- Spring boot自定义启动字符画(banner)
spring boot项目启动时会打印spring boot的ANSI字符画,可以进行自定义. 如何自定义 实现方式非常简单,我们只需要在Spring Boot工程的/src/main/resourc ...
- Kudu之Tablet的发现过程
当创建Kudu客户端时,其会从主服务器上获取tablet位置信息,然后直接与服务于该tablet的服务器进行交谈.为了优化读取和写入路径,客户端将保留该信息的本地缓存,以防止他们在每个请求时需要查询主 ...
- nginx+keepalived实现 负载均衡 高可用
Vip: 192.168.220.18 Rip1:192.168.220.2 Rip:192.168.220.3 Rip可以配置在一个服务器上通过ip做虚拟主机 1 rs上配置环境 2 配置应用 Yu ...