Solution -「国家集训队」「洛谷 P2839」Middle
\(\mathcal{Description}\)
Link.
给定序列 \(\{a_n\}\),\(q\) 组询问,给定 \(a<b<c<d\),求 \(l\le[a,b],r\le[c,d]\) 的子序列 \([l,r]\) 的中位数最大值。若长度为偶数,中位数取中间两数较大的一个。强制在线。
\(n\le2\times10^4\),\(q\le2.5\times10^4\)。
\(\mathcal{Solution}\)
crashed:众所周知,中位数是可以二分的。
考虑单组询问,二分中位数 \(mid\),把序列中大于等于 \(mid\) 的值设为 \(1\),小于 \(mid\) 的值设为 \(0\),求出满足条件的 \([l,r]\) 的序列和的最大值。若最大值是非负数,表明 \(mid\) 可行,且还能增大;否则只能减少。
多组询问,发现对于每个 \(mid\),序列的长相都不尽相同。但序列的变化是极其有限的——当 \(mid\) 递增,每个位置只会又 \(1\) 变为 \(0\) 一次。
由此可以想到主席树。离散化之后,预处理 \(mid=1,2,\dots,n\) 时的序列,建成主席树。树上维护区间和,区间最大前缀,区间最大后缀。处理询问时仍二分 \(mid\),利用以 \(mid\) 为根的这棵权值线段树的信息,求出区间最大和。显然最大和为 \([a,b)\text{最大后缀}+[b,c]\text{之和}+(c,d]\text{最大前缀}\),判断正负情况即可。由于二分时答案会尽量靠右,而最大的答案一定恰好是序列中的某个值,所以不必担心答案不在序列中的情况。
复杂度 \(\mathcal O(n\log^2n)\)。
\(\mathcal{Code}\)
#include <cstdio>
#include <vector>
#include <algorithm>
typedef std::pair<int, int> pii;
const int MAXN = 20000;
int n, a[MAXN + 5], tval[MAXN + 5], root[MAXN + 5];
std::vector<int> apr[MAXN + 5];
inline int rint () {
int x = 0; char s = getchar ();
for ( ; s < '0' || '9' < s; s = getchar () );
for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
return x;
}
inline int max_ ( const int a, const int b ) { return a < b ? b : a; }
struct PersistentSegmentTree {
static const int MAXND = MAXN * 40;
int cntnd, ch[MAXND + 5][2], sum[MAXND + 5], lmx[MAXND + 5], rmx[MAXND + 5];
inline void pushup ( const int rt ) {
sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
lmx[rt] = max_ ( lmx[ch[rt][0]], sum[ch[rt][0]] + lmx[ch[rt][1]] );
rmx[rt] = max_ ( rmx[ch[rt][1]], sum[ch[rt][1]] + rmx[ch[rt][0]] );
}
inline void build ( int& rt, const int l, const int r ) {
rt = ++ cntnd;
if ( l == r ) return sum[rt] = lmx[rt] = rmx[rt] = 1, void ();
int mid = l + r >> 1;
build ( ch[rt][0], l, mid ), build ( ch[rt][1], mid + 1, r );
pushup ( rt );
}
inline void update ( int& rt, const int l, const int r, const int x ) {
int old = rt; rt = ++ cntnd;
ch[rt][0] = ch[old][0], ch[rt][1] = ch[old][1];
sum[rt] = sum[old], lmx[rt] = lmx[old], rmx[rt] = rmx[old];
if ( l == r ) return sum[rt] = -1, lmx[rt] = rmx[rt] = 0, void ();
int mid = l + r >> 1;
if ( x <= mid ) update ( ch[rt][0], l, mid, x );
else update ( ch[rt][1], mid + 1, r, x );
pushup ( rt );
}
inline int qrySum ( const int rt, const int l, const int r, const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return sum[rt];
int mid = l + r >> 1, ret = 0;
if ( ql <= mid ) ret += qrySum ( ch[rt][0], l, mid, ql, qr );
if ( mid < qr ) ret += qrySum ( ch[rt][1], mid + 1, r, ql, qr );
return ret;
}
inline pii qryLmx ( const int rt, const int l, const int r, const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return { lmx[rt], sum[rt] };
int mid = l + r >> 1, ret = 0, s = 0; pii tmp;
if ( ql <= mid ) {
tmp = qryLmx ( ch[rt][0], l, mid, ql, qr );
ret = tmp.first, s = tmp.second;
}
if ( mid < qr ) {
tmp = qryLmx ( ch[rt][1], mid + 1, r, ql, qr );
ret = max_ ( ret, s + tmp.first ), s += tmp.second;
}
return { ret, s };
}
inline pii qryRmx ( const int rt, const int l, const int r, const int ql, const int qr ) {
if ( ql <= l && r <= qr ) return { rmx[rt], sum[rt] };
int mid = l + r >> 1, ret = 0, s = 0; pii tmp;
if ( mid < qr ) {
tmp = qryRmx ( ch[rt][1], mid + 1, r, ql, qr );
ret = tmp.first, s = tmp.second;
}
if ( ql <= mid ) {
tmp = qryRmx ( ch[rt][0], l, mid, ql, qr );
ret = max_ ( ret, s + tmp.first ), s += tmp.second;
}
return { ret, s };
}
} pst;
int main () {
n = rint ();
for ( int i = 1; i <= n; ++ i ) a[i] = tval[i] = rint ();
std::sort ( tval + 1, tval + n + 1 );
int lim = std::unique ( tval + 1, tval + n + 1 ) - tval - 1;
for ( int i = 1; i <= n; ++ i ) {
a[i] = std::lower_bound ( tval + 1, tval + lim + 1, a[i] ) - tval;
apr[a[i]].push_back ( i );
}
pst.build ( root[1], 1, n ); // 注意这里n的意义成为了序列长度,不要与lim搞混。
for ( int i = 2; i <= lim; ++ i ) {
root[i] = root[i - 1];
for ( int p: apr[i - 1] ) pst.update ( root[i], 1, n, p );
}
for ( int q = rint (), ans = 0, tmp[4]; q --; ) {
for ( int i = 0; i < 4; ++ i ) tmp[i] = ( rint () + ans ) % n + 1;
std::sort ( tmp, tmp + 4 );
int l = 1, r = lim;
while ( l <= r ) {
int mid = l + r >> 1;
int cnt = pst.qrySum ( root[mid], 1, n, tmp[1], tmp[2] )
+ pst.qryLmx ( root[mid], 1, n, tmp[2] + 1, tmp[3] ).first
+ pst.qryRmx ( root[mid], 1, n, tmp[0], tmp[1] - 1 ).first;
if ( cnt >= 0 ) l = ( ans = mid ) + 1;
else r = mid - 1;
}
printf ( "%d\n", ans = tval[ans] );
}
return 0;
}
Solution -「国家集训队」「洛谷 P2839」Middle的更多相关文章
- P4827「国家集训队」 Crash 的文明世界
「国家集训队」 Crash 的文明世界 提供一种不需要脑子的方法. 其实是看洛谷讨论版看出来的( (但是全网也就这一篇这个方法的题解了) 首先这是一个关于树上路径的问题,我们可以无脑上点分治. 考虑当 ...
- 「国家集训队」middle
「国家集训队」middle 传送门 按照中位数题的套路,二分答案 \(mid\),序列中 \(\ge mid\) 记为 \(1\),\(< mid\) 的记为 \(-1\) 然后只要存在一个区间 ...
- 「国家集训队」小Z的袜子
「国家集训队」小Z的袜子 传送门 莫队板子题. 注意计算答案的时候,由于分子分母都要除以2,所以可以直接约掉,这样在开桶算的时候也方便一些. 参考代码: #include <algorithm& ...
- 「区间DP」「洛谷P1043」数字游戏
「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...
- 「洛谷1903」「BZOJ2120」「国家集训队」数颜色【带修莫队,树套树】
题目链接 [BZOJ传送门] [洛谷传送门] 题目大意 单点修改,区间查询有多少种数字. 解法1--树套树 可以直接暴力树套树,我比较懒,不想写. 稍微口胡一下,可以直接来一个树状数组套主席树,也就是 ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
- Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\) OurOJ & 洛谷 P4372(几乎一致) 设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...
- Solution -「POI 2010」「洛谷 P3511」MOS-Bridges
\(\mathcal{Description}\) Link.(洛谷上这翻译真的一言难尽呐. 给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...
- Solution -「APIO 2016」「洛谷 P3643」划艇
\(\mathcal{Description}\) Link & 双倍经验. 给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...
随机推荐
- linux .gz文件 压缩与解压缩命令
1. 压缩文件 gzip 源文件 如压缩 b.txt 使用命令 gzip b.txt 注意 压缩为 .gz 文件 源文件会消失 如果想保留源文件 使用命令 gzip -c 源文件 > 压缩文件 ...
- 安装devstack中遇到的一些问题整理
1.执行stack.sh文件后提示 ./stack.sh:528:check_path_perm_sanity /opt/devstack/functions:582:die [ERROR] /opt ...
- 关于 cannot create Parameters: [] 报错问题的解决方法
其实在Sort类中添加无参构造就可以解决 我自己写的是Sort类,其它情况得视你们自己写的类决定 至于为什么也不是很清楚
- SYCOJ411
题面描述 MasMas在面试某大厂时遇到了一道有趣的题.面试官要求MasMas写一个程序找出几个数中,出现次数为奇数的那个数.MasMas抓耳挠腮,请你帮帮他. 输入描述 第一行输入一个数nn (1 ...
- 常用Cron表达式范例
描述 表达式 每隔5秒执行一次 */5 * * * * ? 每隔1分钟执行一次 0 */1 * * * ? 每天23点执行一次 0 0 23 * * ? 每天凌晨1点执行一次 0 0 1 * * ? ...
- 解决windows下因为防火墙无法通过go get 下载gin的问题
使用: go get -u github.com/gin-gonic/gin 出现以下错误: unrecognized import path "gopkg.in/yaml.v2" ...
- 新手如何入门linux,linux原来还可以这么学
前言 在这个只有cangls和小白两人的小房间中,展开了一次关于学习方法的讨论. 小白:cangls啊,我想请教一个问题,您是如何记住那么多linux命令的. cangls:我啊,别人都看我的小电影, ...
- rpc基础讲解
什么是RPC 本地过程调用 远程过程调用带来的3个问题 RPC的调用过程 RPC的具体过程如下 总结 RPC.HTTP.Restful之间的区别 通过httpserver实现rpc 首先一点需要明确: ...
- Android安卓开发-记账本布局
账单页面布局统计页面布局我的页面布局主页面加号记账页面布局.点击记账页面记账类别布局点击收入页面收入类别布局统计页面支出布局统计页面收入布局查询页面布局数据库设计字段一,支出id和收入id分配字段二, ...
- 码风QwQ
注:卡常.压行时怎么有效怎么来QwQ 快读真香.( 不喜欢用字符数组,使用string. 此时cin cout输入前会加这样三句以优化: ios::sync_with_stdio(0); cin.ti ...