当前位置:网站首页>洛谷P2839 [国家集训队]middle(二分 + 主席树 + 区间合并)
洛谷P2839 [国家集训队]middle(二分 + 主席树 + 区间合并)
2022-06-25 06:43:00 【mfy的1号小迷弟】
洛谷P2839 [国家集训队]middle(二分 + 主席树)
题意:
一个长度为 n n n 的序列 a a a,设其排过序之后为 b b b,其中位数定义为 b n / 2 b_{n/2} bn/2 ,其中 a , b a,b a,b 从 0 0 0 开始标号,除法取下整。给你一个长度为 n n n 的序列 s s s。
回答 Q Q Q 个这样的询问: s s s 的左端点在 [ a , b ] [a,b] [a,b] 之间,右端点在 [ c , d ] [c,d] [c,d] 之间的子区间中,最大的中位数。
其中 a < b < c < d a<b<c<d a<b<c<d
位置也从 0 开始标号
思路:
将初始数组从小到大排序排好后,二分中位数的下标x ,判断这个位置的元素是否符合:贪心的想,在 x在[a,d]比a[x]小的数全部变成-1,大的数全变成1,再求和:在[a,b]区间求一个从右端点b开始往左的最大的连续区间和 + [b+1,c-1]和 + 在[c,d]区间求一个从左端点c开始往右的最大的连续区间和。
root[i]表示,比a数组中第i大数小的数已经全部赋值成-1,大的数全部赋值成1。root[i]的i满足连续性,可以二分。
用主席树,先把所有点赋值成1,再按权值从小到大,在相应位置(a数组的初始位置)-1。每次暴力logn的去修改树。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int INF=0x3f3f3f3f;
const int maxn=1e5+6;
int n,m,tot,a[maxn],id[maxn],root[maxn],p[6],pre;
struct NODE{
int sum,ml,mr,l,r;
void init(){
sum=0,ml=mr=-INF;
}
}tr[maxn*400],ANS;
bool cmp(int x,int y){
return a[x]<a[y];
}
void build(int &t,int l,int r){
//动态开点
t=++tot;
tr[t].ml=tr[t].mr=tr[t].sum=r-l+1;
if(l==r)return;
int mid=(l+r)>>1;
build(tr[t].l,l,mid);
build(tr[t].r,mid+1,r);
}
NODE merge(NODE h,NODE x,NODE y){
//
NODE z;
z.l=h.l,z.r=h.r;//初始下标
z.sum=x.sum+y.sum;//sum直接加
z.mr=max(y.mr,y.sum+x.mr);//右区间最大连续和
z.ml=max(x.ml,x.sum+y.ml);//左区间最大连续和
return z;
}
void update(int &t,int l,int r,int x){
tr[++tot]=tr[t],t=tot;
if(l==r){
tr[t].ml=tr[t].mr=tr[t].sum=-1;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(tr[t].l,l,mid,x);
else update(tr[t].r,mid+1,r,x);
tr[t]=merge(tr[t],tr[tr[t].l],tr[tr[t].r]);
}
void query(int t,int l,int r,int x,int y){
if(x<=l&&r<=y){
ANS=merge(ANS,ANS,tr[t]);//将每次查询的结果合并
return;
}
int mid=(l+r)>>1;
if(x<=mid)query(tr[t].l,l,mid,x,y);
if(y>mid)query(tr[t].r,mid+1,r,x,y);
}
bool check(int pos){
int he=0;
if(p[2]+1<=p[3]-1){
ANS.init();//记得初始化
query(root[pos],1,n,p[2]+1,p[3]-1);
he+=ANS.sum;
}
ANS.init();
query(root[pos],1,n,p[1],p[2]);
he+=ANS.mr;
ANS.init();
query(root[pos],1,n,p[3],p[4]);
he+=ANS.ml;
return he>=0;
}
int solve(){
for(int i=1;i<=4;i++)
p[i]=(p[i]+pre)%n+1;//下标从0开始,要+1
sort(p+1,p+1+4);
int l=1,r=n,ans=0;//在id数组下标进行二分
while(l<=r){
int mid=(l+r)>>1;
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
pre=a[id[ans]];
return pre;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
id[i]=i;
}
sort(id+1,id+1+n,cmp);//离散化,将id数组按照 a的大小排序,方便处理
build(root[1],1,n);
for(int i=2;i<=n;i++){
root[i]=root[i-1];
update(root[i],1,n,id[i-1]);
}
scanf("%d",&m);
while(m--){
scanf("%d%d%d%d",&p[1],&p[2],&p[3],&p[4]);
printf("%d\n",solve());
}
}
边栏推荐
- TCP的那点玩意儿
- Six causes of PCB disconnection 2021-10-20
- Bicubic difference
- Linux上oracle和mysql的启动,关闭,重启
- FM信号、调制信号和载波
- El input to add words to the tail
- ts环境搭建
- Advantages and differences of three kinds of vias in PCB 2021-10-27
- C get the version number of exe - file version and assembly version
- Tips 𞓜 how to clean PCB boards 2021-10-22
猜你喜欢

PCB board design - automatic layout 2021-10-15

微信小程序开通客服消息功能开发

How to use ad wiring for PCB design?

DNS协议及其DNS完整的查询过程

新版USBCAN卡CAN分析仪的CAN&CANFD综合测试分析软件LKMaster主要功能介绍

Knowledge sharing 𞓜 conventional laminated structure of six layer PCB

將數據導入到MATLAB

一次弄清楚 Handler 可能导致的内存泄漏和解决办法

El input to add words to the tail

Manufacturing process of PCB 2021-10-11
随机推荐
Modular programming of oled12864 display controlled by single chip microcomputer
How to resize an image in C #
Microsoft Office Word 远程命令执行漏洞(CVE-2022-30190)分析与利用
剑指offer刷题(简单等级)
一次弄清楚 Handler 可能导致的内存泄漏和解决办法
【红旗杯?】补题
Tips 𞓜 how to clean PCB boards 2021-10-22
协议和服务的区别?
1742. 盒子中小球的最大数量
使用报文和波形记录分析仪RoyalScope的帧统计功能排查CAN总线偶发性故障
Mysql面试-执行sql响应比较慢,排查思路。
SCM Project Training
MySQL interview - the response of executing SQL is relatively slow, and the troubleshooting ideas.
微信小程序开通客服消息功能开发
Ph中和过程建模
Terms and concepts related to authority and authentication system
基于RBAC 的SAAS系统权限设计
取消word文档中某些页面的页眉
57. 插入区间
Misunderstanding of switching triode