Luogu 2839 [国家集训队]middle
感觉这题挺好的。
首先对于中位数最大有一个很经典的处理方法就是二分,每次二分一个数组中的下标$mid$,然后我们把$mid$代回到原来的数组中检查,如果一个数$a_{i} \geq mid$,那么就把$s_{i}$记为$1$,否则把$s_{i}$记为$-1$,然后对$s_{i}$跑一遍前缀和,观察是否有一个区间的和不小于$0$。
读清楚题意之后发现在这题中,如果要对一个长度为偶数(记为$n$)的序列求中位数,那么答案为排好序的数组中下标为$n / 2 + 1$的元素。(下标从$1$开始),不同的中位数$s_{i}$的表示方法可能有少许不同,要具体题目具体yy。
证明应当也很简单,$+1$代表一个比当前的$mid$大的数,而$-1$表示一个比当前的$a_{mid}$小的数,那么当$a_{mid}$是中位数的条件在一个区间成立的时候,这个区间的$s_{i}$和应当恰好等于$0$。而当得到了一个区间和大于$0$的区间的时候,我们可以通过扔掉几个$1$使它变成$0$,相当于之前的条件成立。
但是这样还是太慢了。
对于本题来说,每次二分得到了一个$mid$,我们检验的时候得到的答案就一定是(区间是$a, b, c, d$)$sum(b + 1, c - 1) + lmax(c, d) + rmax(a, b)$。
其中$lmax$代表一定要选左端点的最大子段和,而$rmax$代表一定要选右端点的最大子段和。
显然可以用线段树来维护。
一个元素开一颗线段树是不可能的……
我们发现在排好序中的数组里面两个下标相差$1$的元素的值其实只有$1$个不同,这就是较小的元素在原数组中的下标,那么大多数结点的值可以继承过来。
于是可以可持久化了,变成了一个主席树。
时间复杂度$O(nlog^{2}n)$。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 2e4 + ;
const int inf = << ; int n, qn, a[N]; struct Innum {
int val, id;
} b[N]; bool cmp(const Innum &x, const Innum &y) {
if(x.val != y.val) return x.val < y.val;
else return x.id < y.id;
} /*bool cmp(const Innum &x, const Innum &y) {
return x.val < y.val;
} */ inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline int max(int x, int y) {
return x > y ? x : y;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} namespace PSegT {
struct Node {
int lc, rc, sum, lmax, rmax; inline void init() {
lc = rc = sum = ;
lmax = rmax = -inf;
} } s[N * ]; int root[N], nodeCnt = ; #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define lmax(p) s[p].lmax
#define rmax(p) s[p].rmax
#define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
sum(p) = sum(lc(p)) + sum(rc(p));
// lmax(p) = rmax(p) = -inf;
lmax(p) = max(lmax(lc(p)), lmax(rc(p)) + sum(lc(p)));
rmax(p) = max(rmax(rc(p)), rmax(lc(p)) + sum(rc(p)));
} void build(int &p, int l, int r) {
p = ++nodeCnt;
if(l == r) {
sum(p) = lmax(p) = rmax(p) = ;
return;
} build(lc(p), l, mid);
build(rc(p), mid + , r);
up(p);
} void modify(int &p, int l, int r, int x, int v, int pre) {
s[p = ++nodeCnt] = s[pre];
if(l == r) {
sum(p) = lmax(p) = rmax(p) = v;
return;
} if(x <= mid) modify(lc(p), l, mid, x, v, lc(pre));
else modify(rc(p), mid + , r, x, v, rc(pre));
up(p);
} Node query(int p, int l, int r, int x, int y) {
if(x <= l && y >= r) return s[p]; Node res, ln, rn;
res.init(), ln.init(), rn.init(); if(x <= mid) ln = query(lc(p), l, mid, x, y);
if(y > mid) rn = query(rc(p), mid + , r, x, y); res.sum = ln.sum + rn.sum;
res.lmax = max(ln.lmax, ln.sum + rn.lmax);
res.rmax = max(rn.rmax, rn.sum + ln.rmax); return res;
} #undef lc
#undef rc
#undef sum
#undef lmax
#undef rmax
#undef mid } using namespace PSegT; inline bool chk(int mid, int l1, int r1, int l2, int r2) {
Node now; int res = ; if(r1 + <= l2 - ) {
now.init();
now = query(root[mid], , n, r1 + , l2 - );
res += now.sum;
} now.init();
now = query(root[mid], , n, l1, r1);
res += now.rmax; now.init();
now = query(root[mid], , n, l2, r2);
res += now.lmax; return res >= ;
} inline int solve(int l1, int r1, int l2, int r2) {
int ln = , rn = n, mid, res;
for(; ln <= rn; ) {
mid = (ln + rn) / ;
if(chk(mid, l1, r1, l2, r2)) res = mid, ln = mid + ;
else rn = mid - ;
}
return b[res].val;
} int main() {
read(n);
for(int i = ; i <= n; i++) {
read(a[i]);
b[i].val = a[i], b[i].id = i;
} s[].lmax = s[].rmax = -inf;
build(root[], , n);
sort(b + , b + + n, cmp);
for(int i = ; i <= n; i++)
modify(root[i], , n, b[i - ].id, -, root[i - ]); read(qn);
for(int ans = , q[]; qn--; ) {
for(int i = ; i < ; i++) {
read(q[i]);
q[i] = (q[i] + ans) % n + ;
}
sort(q, q + );
ans = solve(q[], q[], q[], q[]);
printf("%d\n", ans);
} return ;
}
Luogu 2839 [国家集训队]middle的更多相关文章
- [洛谷2839/国家集训队]middle
Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之 ...
- Luogu P2839 [国家集训队]middle
题目 首先我们考虑解决中位数一类问题的常用手段:二分\(mid\),将大于等于它的设为\(1\),小于它的设为\(−1\),判断区间和是否\(\ge0\). 对于询问\(a,b,c,d\),二分完\( ...
- [国家集训队]middle 解题报告
[国家集训队]middle 主席树的想法感觉挺妙的,但是这题数据范围这么小,直接分块草过去不就好了吗 二分是要二分的,把\(<x\)置\(-1\),\(\ge x\)的置\(1\),于是我们需要 ...
- [国家集训队]middle
[国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...
- luogu P2757 [国家集训队]等差子序列
题目链接 luogu P2757 [国家集训队]等差子序列 题解 线段树好题 我选择暴力 代码 // luogu-judger-enable-o2 #include<cstdio> inl ...
- P2839 [国家集训队]middle
P2839 [国家集训队]middle 好妙的题啊,,,, 首先二分一个答案k,把数列里>=k的数置为1,=0就是k>=中位数,<0就是k<中位数 数列的最大和很好求哇 左边的 ...
- luogu P2619 [国家集训队2]Tree I
题目链接 luogu P2619 [国家集训队2]Tree I 题解 普通思路就不说了二分增量,生成树check 说一下坑点 二分时,若黑白边权有相同,因为权值相同优先选白边,若在最有增量时出现黑白等 ...
- CF484E Sign on Fence && [国家集训队]middle
CF484E Sign on Fence #include<bits/stdc++.h> #define RG register #define IL inline #define _ 1 ...
- 【LG2839】[国家集训队]middle
[LG2839][国家集训队]middle 题面 洛谷 题解 按照求中位数的套路,我们二分答案\(mid\),将大于等于\(mid\)的数设为\(1\),否则为\(-1\). 若一个区间和大于等于\( ...
随机推荐
- systemverilog FAQ(zz)
1. What is clocking block? Ans: Clocking block can be declared using the keywords clocking and endcl ...
- mini2440移植uboot 2014.04(三)
我修改的代码已经上传到github上,地址:https://github.com/qiaoyuguo/u-boot-2014.04-mini2440.git 参考文档: s3c2440手册(下载地址) ...
- Spring Cloud之Feign客户端超时时间配置
关于雪崩效应: 默认情况下tomcat只有一个线程去处理客户端发送的所有请求.高并发情况下,如果客户端请求都在同一接口,tomcat的所有线程池去处理,导致其他接口服务访问不了,等待. Tomcat有 ...
- win7 apache+openssl 安装
win7 apache+openssl 安装 博客分类: win7 apache+openssl 安装 win7 apache+openssl 安装 注:附件提供包含apache和openssl的安 ...
- 织梦dedecms 扩展channel栏目标签 获取交叉栏目名称和链接
channel栏目标签默认有调用顶级栏目(top).子栏目(son).同级栏目(self),那想获取交叉栏目的名称和链接怎么获取呢? 其实在原来的代码上改一下就可以了.下面是具体代码.打开文件chan ...
- js 判断滚动条的滚动方向
以下代码实现判断页面的滚动条的滚动方向: var sign = 80;//定义默认的向上滚与向下滚的边界 window.onscroll = window.onresize = function(){ ...
- window.showModalDialog()之返回值
window.showModalDialog的基本用法 showModalDialog() (IE 4+ 支持) showModelessDialog() (IE 5+ 支持) window.show ...
- Python — pandas
Pandas有两种数据结构:Series和DataFrame. 1.Series Series类似于一维数组,和numpy的array接近,由一组数据和数据标签组成.数据标签有索引的作用.数据标签是p ...
- Linux vi/vim使用方法
vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令. 1.vi的基本概念 基本上vi ...
- sublime text _注册码
转自:https://9iphp.com/web/html/sublime-text-3-license-key.html 使用方法 打开 Sublime Text 3 的 “Help”–“Enter ...