Luogu2839 Middle 主席树、二分答案
题目传送门:https://www.luogu.org/problemnew/show/P2839
题目大意:给出一个长度为$N$的序列与$Q$次询问,每次询问左端点在$[a,b]$,右端点在$[c,d]$的区间中最大的中位数,强制在线(本题中的中位数定义与平常不同,设某区间长度为$L$,则在从小到大排序后的序列中(编号从$0$开始),其中位数为第$\lfloor L/2 \rfloor$号元素)$N,Q \leq 2 \times 10^4$
这鬼题让我知道主席树可以用于除第$K$大以外的问题$qwq$
观察$100 \%$的数据规模,$O(nQ)$的做法都比较吃力,所以考虑使用$log$数据结构进行维护获得$O(Qlogn)$或者$O(Qlog^2n)$的算法。故考虑到使用线段树进行维护,同时使用二分的方式寻找每个询问的答案,
其中check的内容就是寻找是否有满足该询问条件的区间,在其中(大于等于当前二分的数的数字个数)要大于等于(小于当前二分的数的数字个数)。断句略奇怪
不妨将大于等于当前二分的数的数字的权值设为1,小于当前二分的数的数字的权值设为-1,check的内容就等价于询问$$max(\sum_{i=x}^y w_i) \geq 0 (x \in {[a , b]} , y \in{[c , d]})$$是否成立。
所以想到对于每个数字建立一个线段树存储权值,在每一次二分询问时求出对应线段树中$x \in {[a , b]} , y \in{[c , d]},\sum_{i=b+1}^{c-1} w_i + max(\sum_{i=x}^b w_i)+max(max(\sum_{i=c}^y w_i))$是否大于0,刚好这三个式子对应区间和、区间最大后缀、区间最大前缀,可以使用线段树解决。
然后发现对于排序后的相邻两数只有一个$1$变成$-1$,就可以使用主席树将空间压到允许范围内了
时间复杂度为$O(Qlog^2n)$,空间复杂度为$O(nlogn)$,符合本题数据范围
#include<bits/stdc++.h>
#define MAXN 100002
using namespace std;
inline int read(){
;
;
char c = getchar();
while(!isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(isdigit(c)){
a = (a << ) + (a << ) + (c ^ ');
c = getchar();
}
return f ? -a : a;
}
];
inline void print(int x){
;
)
fwrite( , stdout);
else{
){
x = -x;
fwrite( , stdout);
}
while(x){
output[--dirN] = x % + ;
x /= ;
}
fwrite(output + dirN , , strlen(output + dirN) , stdout);
}
fwrite( , , stdout);
}
struct node{
int sum , lMax , rMax , l , r;
}Tree[ * MAXN];
struct sortNum{//用于排序
int ind , num;
bool operator <(sortNum a){
return num < a.num;
}
}sorted[MAXN];
int num[MAXN] , root[MAXN];
, rMax , rSum , lMax , lSum;
inline int max(int a , int b){
return a > b ? a : b;
}
inline void swap(int &a , int &b){
int t = a;
a = b;
b = t;
}
//初始化一个所有叶子结点权值都为1的线段树
void init(int dir , int l , int r){
Tree[dir].sum = Tree[dir].lMax = Tree[dir].rMax = r - l + ;
if(l != r){
init(Tree[dir].l = ++cntNode , l , l + r >> );
init(Tree[dir].r = ++cntNode , (l + r >> ) + , r);
}
}
inline void pushup(int dir){
Tree[dir].lMax = max(Tree[Tree[dir].l].lMax , Tree[Tree[dir].l].sum + Tree[Tree[dir].r].lMax);
Tree[dir].rMax = max(Tree[Tree[dir].r].rMax , Tree[Tree[dir].r].sum + Tree[Tree[dir].l].rMax);
Tree[dir].sum = Tree[Tree[dir].l].sum + Tree[Tree[dir].r].sum;
}
//更新版本
void update(int now , int last , int l , int r , int dir){
if(l == r){
Tree[now].lMax = Tree[now].rMax = ;
Tree[now].sum = -;
}
else{
){
Tree[now].l = Tree[last].l;
update(Tree[now].r = ++cntNode , Tree[last].r , (l + r >> ) + , r , dir);
}
else{
Tree[now].r = Tree[last].r;
update(Tree[now].l = ++cntNode , Tree[last].l , l , l + r >> , dir);
}
pushup(now);
}
}
//区间和
int findSum(int dir , int l , int r , int L , int R){
if(L >= l && R <= r)
return Tree[dir].sum;
;
)
sum += findSum(Tree[dir].l , l , r , L , L + R >> );
)
sum += findSum(Tree[dir].r , l , r , (L + R >> ) + , R);
return sum;
}
//区间最大后缀
void findRightMax(int dir , int l , int r , int L , int R){
if(L >= l && R <= r){
rMax = max(rMax , Tree[dir].rMax + rSum);
rSum += Tree[dir].sum;
return;
}
)
findRightMax(Tree[dir].r , l , r , (L + R >> ) + , R);
)
findRightMax(Tree[dir].l , l , r , L , L + R >> );
}
//区间最大前缀
void findLeftMax(int dir , int l , int r , int L , int R){
if(L >= l && R <= r){
lMax = max(lMax , Tree[dir].lMax + lSum);
lSum += Tree[dir].sum;
return;
}
)
findLeftMax(Tree[dir].l , l , r , L , L + R >> );
)
findLeftMax(Tree[dir].r , l , r , (L + R >> ) + , R);
}
//二分check
//为了方便处理这里的代码与上面的公式稍有不同
inline bool check(int mid , int a , int b , int c , int d){
lSum = rSum = ;
lMax = rMax = -;
findRightMax(root[mid] , a , b - , , N);
findLeftMax(root[mid] , c + , d , , N);
, N) + lMax + rMax >= ;
}
int main(){
N = read();
;
; i <= N ; i++)
num[sorted[i].ind = i] = sorted[i].num = read();
init(root[] = , , N);
sort(sorted + , sorted + N + );
; i <= N ; i++)
update(root[i + ] = ++cntNode , root[i] , , N , sorted[i].ind);
for(int Q = read() ; Q ; Q--){
, b = (read() + lastans) % N + , c = (read() + lastans) % N + , d = (read() + lastans) % N + ;
if(a > b)
swap(a , b);
if(a > c)
swap(a , c);
if(a > d)
swap(a , d);
if(b > c)
swap(b , c);
if(b > d)
swap(b , d);
if(c > d)
swap(c , d);
, r = N;
while(l < r){
>> ;
if(check(mid , a , b , c , d))
l = mid;
else
r = mid - ;
}
printf("%d\n" , lastans = sorted[l].num);
}
;
}
Luogu2839 Middle 主席树、二分答案的更多相关文章
- BZOJ 2653: middle(主席树+二分答案)
传送门 解题思路 首先可以想到一种暴力做法,就是询问时二分,然后大于等于这个值的设为1,否则设为-1,然后就和GSS1那样统计答案.但是发现这样时间空间复杂度都很爆炸,所以考虑预处理,可以用主席树来做 ...
- 【bzoj2653】【middle】【主席树+二分答案】
Description 一个长度为 n 的序列 a ,设其排过序之后为 b ,其中位数定义为 b[n/2] ,其中 a,b 从 0 开始标号 , 除法取下整. 给你一个长度为 n 的序列 s .回答 ...
- bzoj 2653: middle (主席树+二分)
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2522 Solved: 1434[Submit][Status][Disc ...
- [BZOJ2653]middle 主席树+二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2042 Solved: 1123[Submit][Status][Disc ...
- BZOJ 1926: [Sdoi2010]粟粟的书架(主席树,二分答案)
BZOJ 1926: [Sdoi2010]粟粟的书架(主席树,二分答案) 题意 : 给你一个长为\(R\)宽为\(C\)的矩阵,第\(i\)行\(j\)列的数为\(P_{i,j}\). 有\(m\)次 ...
- BZOJ5343[Ctsc2018]混合果汁——主席树+二分答案
题目链接: CTSC2018混合果汁 显然如果美味度高的合法那么美味度低的一定合法,因为美味度低的可选方案包含美味度高的可选方案. 那么我们二分一个美味度作为答案然后考虑如何验证? 选择时显然要贪心的 ...
- P4094 [HEOI2016/TJOI2016]字符串 后缀数组+主席树+二分答案
$ \color{#0066ff}{ 题目描述 }$ 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须 ...
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案
Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...
- HDU - 6621 K-th Closest Distance 主席树+二分答案
K-th Closest Distance 主席树第二波~ 题意 给你\(n\)个数\(m\)个询问,问\(i\in [l,r]\)计算每一个\(|a_{i}-p|\)求出第\(k\)小 题目要求强制 ...
随机推荐
- Windows下更新 npm 和 nodejs
一.更新npm // 将npm更新到最新版本 npm install npm@latest -g 二.更新nodejs 1. 首先通过 where node 命令找到nodejs的安装路径 2. 然后 ...
- python自动化开发-6-面向对象编程
面向对象编程 面向对象的特性 封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏. 继承:面向对象编程 (OOP) 语言的一个主要功能就是“ ...
- 异步 Apex 类
异步Apex类 一个Apex类可以定义为异步类,用于异步执行. 异步类可以通过多种方式实现: Future注解 批处理 Queueable接口 Schedulable接口 Future注解 使用Fut ...
- python 遇到的小坑
由于前端资源紧缺,我的后端系统迟迟等不来它的前端,没办法只好自己来写了.从html,js入门学起,然后照着vue.js的官方教程写了几个实例,从github上clone了一个不错的vue.js模版,填 ...
- python常用模块之re模块(正则)
python种的re模块常用的5种方法,分别是re.match re.search re.findall re.split re.sub. 在介绍五种方法之前,需要介绍一下正则的基础. . ...
- 给电脑插上无线网卡,变成路由器----Windows系统承载网络的使用
1. 以管理员身份运行命令提示符(PowerShell) 2. 启用并设定虚拟wifi网卡 netsh wlan set hostednetwork mode=allow ssid=wifi名称 ke ...
- JMeter乱码常见的解决方案
方法一.直接将JMeter中http请求中Content encoding改为utf-8 方法二.编辑JMeter安装目录:apache-jmeter-3.2\bin中的jmeter.properti ...
- dell r420 H310/H810阵列配置教程及常见问题
进入H310/H810阵列卡BIOS界面 阵列卡管理快捷键 如何创建RAID0和RAID1和RAID5 阵列修复篇 Foreign(外来)状态的硬盘应如何处理 1.进入H310/H810阵列卡BIOS ...
- 【PAT】B1042 字符统计(20 分)
/* 15分的题很简单,但是自己写的时候在输入数据时没有考虑好下标 另外有忘记了输入字符时考虑是否有\n */ #include<stdio.h> #include<algorith ...
- AMP架构补充与wordpress部署
1.httpd的虚拟主机不能使用的问题 httpd中新建一个虚拟主机,并添加访问URI路径的时候,需要给此路径指定访问权限.今天遇到一个虚拟主机不能使用的问题,语法检测没有报错,并且还可以正常启动服务 ...