Luogu2839 [国家集训队]middle 题解
题目很好,考察对主席树的深入理解与灵活运用。
首先看看一般解决中位数的思路,我们二分一个 \(mid\),将区间中 \(\ge mid\) 的数置为 \(1\),小于的置为 \(-1\),然后求区间和,若大于等于零则 \(mid\) 还能增大,否则减小。
现在就有了两个问题:第一,区间不固定;第二,每次二分一个答案就要重构区间,复杂度爆炸。
现在我们来仔细分析一下主席树的结构,首先,它是一个每个点都建了一棵线段树,形成前缀和的形式;每棵线段树又与区间有关。抽象地说,我们可以把第一个特征看作解决时间这一维限制,第二个特征解决位置这一维限制,即主席树同时解决了两维限制。
那再来找找这题的两维限制。如果我们把每次二分看做时间先后的操作,将每次二分的值作为一个“点”建线段树,就相当于预处理出了每次二分后区间的情况,省去了重构。再把权值离散化,那么就映射到了 \(1\sim n\) 的区间,对于 \(mid+1\),显然只有 \(mid\) 这个权值由 \(1\) 变成了 \(-1\) ,这其实只是一个单点修改的操作,这样就解决了第二个问题。
对于第一个问题,我们可以用最大子段和的思路维护 \(lmax,rmax,sum\) 的 tag,那么对于题目给出的区间 \([a,b],[c,d]\) ,答案即是 \([a,b]\) 的 \(rmax\)、\([b+1,c-1]\) 的 \(sum\),\([c,d]\) 的 \(lmax\) 之和。
哪里没有讲清楚可以看代码进一步理解。
#include <bits/stdc++.h>
#define l(x) t[x].l
#define r(x) t[x].r
using namespace std;
const int N=1e5+5;
struct Tree
{
int l,r,lmax,rmax,sum;
void clear() {lmax=rmax=-N,l=r=sum=0;}
}t[N*20],Ans;
int n,Q,a[N],q[4],root[N],cntnode,id[N],ans;
void build(int &rt,int l,int r)
{
t[rt=++cntnode]=(Tree){0,0,r-l+1,r-l+1,r-l+1};
if(l==r) return; int mid=l+r>>1;
build(l(rt),l,mid); build(r(rt),mid+1,r);
}
inline void pushup(int rt)
{
t[rt].lmax=max(t[l(rt)].lmax,t[l(rt)].sum+t[r(rt)].lmax);
t[rt].rmax=max(t[r(rt)].rmax,t[r(rt)].sum+t[l(rt)].rmax);
t[rt].sum=t[l(rt)].sum+t[r(rt)].sum;
}
void Insert(int &rt,int pre,int l,int r,int pos)
{
t[rt=++cntnode]=t[pre];
if(l==r) {t[rt].lmax=t[rt].rmax=t[rt].sum=-1; return;}
int mid=l+r>>1;
if(pos<=mid) Insert(l(rt),l(pre),l,mid,pos);
else Insert(r(rt),r(pre),mid+1,r,pos);
pushup(rt);
}
void query(int rt,int lc,int rc,int l,int r)
{
if(l<=lc&&r>=rc)
{
Ans.lmax=max(Ans.lmax,Ans.sum+t[rt].lmax);
Ans.rmax=max(t[rt].rmax,Ans.rmax+t[rt].sum);
Ans.sum+=t[rt].sum;
return;
}
int mid=lc+rc>>1;
if(l<=mid) query(l(rt),lc,mid,l,r);
if(r>mid) query(r(rt),mid+1,rc,l,r);
}
bool check(int mid)
{
int res=0;
if(q[1]+1<=q[2]-1)
Ans.clear(),query(root[mid],1,n,q[1]+1,q[2]-1),res+=Ans.sum;
Ans.clear(),query(root[mid],1,n,q[0],q[1]),res+=Ans.rmax;
Ans.clear(),query(root[mid],1,n,q[2],q[3]),res+=Ans.lmax;
return res>=0;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",a+i),id[i]=i;
build(root[1],1,n);
sort(id+1,id+n+1,[](int x,int y){return a[x]<a[y];});
for(int i=2;i<=n;++i) Insert(root[i],root[i-1],1,n,id[i-1]);
scanf("%d",&Q);
while(Q--)
{
for(int i=0;i<4;++i)
scanf("%d",q+i),q[i]=(q[i]+ans)%n+1;
sort(q,q+4); int l=1,r=n;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) ans=a[id[mid]],l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}
Luogu2839 [国家集训队]middle 题解的更多相关文章
- luogu2839 [国家集训队]middle
题目链接:洛谷 题目大意:给定一个长度为$n$的序列,每次询问左端点在$[a,b]$,右端点在$[c,d]$的所有子区间的中位数的最大值.(强制在线) 这里的中位数定义为,对于一个长度为$n$的序列排 ...
- 【LG2839】[国家集训队]middle
[LG2839][国家集训队]middle 题面 洛谷 题解 按照求中位数的套路,我们二分答案\(mid\),将大于等于\(mid\)的数设为\(1\),否则为\(-1\). 若一个区间和大于等于\( ...
- [国家集训队]middle 解题报告
[国家集训队]middle 主席树的想法感觉挺妙的,但是这题数据范围这么小,直接分块草过去不就好了吗 二分是要二分的,把\(<x\)置\(-1\),\(\ge x\)的置\(1\),于是我们需要 ...
- [国家集训队]middle
[国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...
- P2839 [国家集训队]middle
P2839 [国家集训队]middle 好妙的题啊,,,, 首先二分一个答案k,把数列里>=k的数置为1,=0就是k>=中位数,<0就是k<中位数 数列的最大和很好求哇 左边的 ...
- CF484E Sign on Fence && [国家集训队]middle
CF484E Sign on Fence #include<bits/stdc++.h> #define RG register #define IL inline #define _ 1 ...
- [洛谷P2839][国家集训队]middle
题目大意:给你一个长度为$n$的序列$s$.$Q$个询问,问在$s$中的左端点在$[a,b]$之间,右端点在$[c,d]$之间的子段中,最大的中位数. 强制在线. 题解:区间中位数?二分答案,如果询问 ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- 解题:国家集训队 Middle
题面 求中位数的套路:二分,大于等于的设为1,小于的设为-1 于是可以从小到大排序后依次加入可持久化线段树,这样每次只会变化一个位置 那左右端点是区间怎么办? 先把中间的算上,然后维护每个区间左右两侧 ...
随机推荐
- 深入理解java虚拟机笔记Chapter2
java虚拟机运行时数据区 首先获取一个直观的认识: 程序计数器 线程私有.各条线程之间计数器互不影响,独立存储. 当前线程所执行的字节码行号指示器.字节码解释器工作时通过改变这个计数器值选取下一条需 ...
- 手把手教你彻底理解MySQL的explain关键字
数据库是程序员必备的一项基本技能,基本每次面试必问.对于刚出校门的程序员,你只要学会如何使用就行了,但越往后工作越发现,仅仅会写sql语句是万万不行的.写出的sql,如果性能不好,达不到要求,可能会阻 ...
- 《CNN Image Retrieval in PyTorch: Training and evaluati-ng CNNs for Image Retrieval in PyTorch》代码思路解读
这是一个基于微调卷积神经网络的图像检索的代码实现,这里我就基于代码做一个实现思路的个人解读,如果有不对的地方或者不够详细的地方,欢迎大家指出. 代码的GitHub地址:filipradenovic/c ...
- 为什么我严重不建议去培训机构参加SAP培训?
欢迎关注微信公众号:sap_gui (ERP咨询顾问之家) 关于是否要参加SAP培训的话题已经是老生常谈了,知乎上随便一搜有好多人在问是否要去参加SAP培训,底下已经有很多人在上面给出了正确建议.但也 ...
- 01 . Varnish简介,原理,配置缓存
简介 Varnish是高性能开源的反向代理服务器和HTTP缓存服务器,其功能与Squid服务器相似,都可以用来做HTTP缓存.可以安装 varnish 在任何web前端,同时配置它缓存内容.与传统的 ...
- 十亿级流量下,我与Redis时延小突刺的战斗史
一.背景 某一日收到上游调用方的反馈,提供的某一个Dubbo接口,每天在固定的时间点被短时间熔断,抛出的异常信息为提供方dubbo线程池被耗尽.当前dubbo接口日请求量18亿次,报错请求94W/天, ...
- csp-s模拟测试52-53
留坑.... 改完题再说吧. 留坑....最近考得什么鬼??模拟53T1 u(差分) 一道差分题????然而考场没有想到如何维护斜率上的差分,事后经miemeng和cyf的生(xuan)动(xue)讲 ...
- 「模拟8.19 A嚎叫..(set) B主仆..(DFS) C征程..(DP+堆优化)」
为啥这一套题目背景感到很熟悉. T1 嚎叫响彻在贪婪的厂房 考试一个小时没调出来,自闭了.......... 正解很好想,最后实在打不出来了只好暴力骗分了... 联想到以前做的题:序列(涉及质因数分 ...
- Pandas高级教程之:处理text数据
目录 简介 创建text的DF String 的方法 columns的String操作 分割和替换String String的连接 使用 .str来index extract extractall c ...
- Python进程和线程实例详解
前言 进程是什么? 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需 ...