http://www.lydsy.com/JudgeOnline/problem.php?id=2653

Description

一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

Input

第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
输入保证满足条件。

Output

Q行依次给出询问的答案。

Sample Input

5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0

Sample Output

271451044
271451044
969056313

——————————————————————————

debug真爽……一会再讲我神奇的debug经历。

(因为参照代码太多了所以就不一一贴了)

我们考虑如何求一个数比中位数大还是小。

方法很简单:将小于该数的数一律变成-1,大于等于的变为1,求和,如果和>=0即*可能为*这个数。

也就是说,我们可以用这个方法二分答案来求得中位数。

那么我们对于一组询问a,b,c,d,判断x与中位数的大小关系,就可以是求最大子序列和的过程了。

那么我们按照元素下标建线段树,并且存储每个区间的最大左/右连续和,,每个区间的和。

那么答案就是(ab最大右连续和)+(bc和)+(cd最大左连续和)。

但是我们不可能为每一组询问重新开一棵线段树,所以我们需要一种*预处理*所有可能的线段树的方法。

于是我们想到了主席树。

我们先对数列排序,这样假设我们中位数下标(以下都是排序后的新下标)为x,则显然0~x-1都是-1,而x~n-1都是1

那么我们的建树过程无非就是第一棵树全是1,而后的树对于前面的树的值都更新为-1就可以了。

(看着复杂,代码也复杂,debug1h一无所获,最后我精简代码发现我i和j搞反了……)

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int N=;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct tree{
int l,r,sum,lx,rx;
}tr[N*];
struct num{
int v,p;
}a[N];
int rt[N],n,m,q,pool,p[];
bool cmp(num f,num s){return f.v<s.v;}
inline void update(int x){
tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum;
tr[x].lx=max(tr[tr[x].l].lx,tr[tr[x].l].sum+tr[tr[x].r].lx);
tr[x].rx=max(tr[tr[x].r].rx,tr[tr[x].r].sum+tr[tr[x].l].rx);
return;
}
inline void build(int &x,int l,int r){
x=++pool;
if(l==r){
tr[x].sum=tr[x].lx=tr[x].rx=;
return;
}
int mid=(l+r)>>;
build(tr[x].l,l,mid);
build(tr[x].r,mid+,r);
update(x);
return;
}
inline void insert(int y,int &x,int l,int r,int p,int v){
tr[x=++pool]=tr[y];
if(l==r){
tr[x].sum=tr[x].lx=tr[x].rx=v;
return;
}
int mid=(l+r)>>;
if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p,v);
else insert(tr[y].r,tr[x].r,mid+,r,p,v);
update(x);
return;
}
inline int query_all(int k,int l,int r,int l1,int r1){
if(l==l1&&r==r1)return tr[k].sum;
int mid=(l+r)>>;
if(r1<=mid) return query_all(tr[k].l,l,mid,l1,r1);
else if(l1>mid) return query_all(tr[k].r,mid+,r,l1,r1);
else return query_all(tr[k].l,l,mid,l1,mid)+query_all(tr[k].r,mid+,r,mid+,r1);
}
inline int query_l(int k,int l,int r,int l1,int r1){
if(l==l1&&r==r1)return tr[k].lx;
int mid=(l+r)>>;
if(r1<=mid) return query_l(tr[k].l,l,mid,l1,r1);
else if(l1>mid) return query_l(tr[k].r,mid+,r,l1,r1);
else return max(query_l(tr[k].l,l,mid,l1,mid),query_all(tr[k].l,l,mid,l1,mid)+query_l(tr[k].r,mid+,r,mid+,r1));
}
inline int query_r(int k,int l,int r,int l1,int r1){
if(l==l1&&r==r1)return tr[k].rx;
int mid=(l+r)>>;
if(r1<=mid) return query_r(tr[k].l,l,mid,l1,r1);
else if(l1>mid) return query_r(tr[k].r,mid+,r,l1,r1);
else return max(query_r(tr[k].r,mid+,r,mid+,r1),query_all(tr[k].r,mid+,r,mid+,r1)+query_r(tr[k].l,l,mid,l1,mid));
}
bool pan(int k){
int sum=;
if(p[]+<p[])sum+=query_all(rt[k],,n-,p[]+,p[]-);
sum+=query_r(rt[k],,n-,p[],p[]);
sum+=query_l(rt[k],,n-,p[],p[]);
return sum>=;
}
int erfen(){
int l=,r=n-,ans;
while(l<=r){
int mid=(l+r)>>;
if(pan(mid)){
ans=a[mid].v;
l=mid+;
}else r=mid-;
}
return ans;
}
int main(){
n=read();
for(int i=;i<n;i++){
a[i].v=read();
a[i].p=i;
}
sort(a,a+n,cmp);
build(rt[],,n-);
for(int i=;i<n;i++)insert(rt[i-],rt[i],,n-,a[i-].p,-);
q=read();
int pre=;
for(int i=;i<=q;i++){
for(int j=;j<;j++)p[j]=(read()+pre)%n;
sort(p,p+);
printf("%d\n",pre=erfen());
}
return ;
}

BZOJ2653:middle——题解的更多相关文章

  1. BZOJ2653 middle 【主席树】【二分】*

    BZOJ2653 middle Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样 ...

  2. 题解【bzoj2653 middle】

    Description 给你一个序列,每次询问给出四个数 \(a,b,c,d\),求所有区间 \([l,r]\) 满足 \(l \in [a,b], r \in [c,d]\) 的中位数的最大值.强制 ...

  3. bzoj2653: middle

    首先,对于每个询问,我们二分答案 然后对于序列中大于等于中位数的数,我们把它们置为1,小于中位数的数,置为-1 那么如果一个区间和大于等于0,那么就资磁,否则就不滋磁 这个区间和呢,我们可以用主席树维 ...

  4. BZOJ2653 middle(二分答案+主席树)

    与中位数有关的题二分答案是很常用的trick.二分答案之后,将所有大于它的看成1小于它的看成-1,那么只需要判断是否存在满足要求的一段和不小于0. 由于每个位置是1还是-1并不固定,似乎不是很好算.考 ...

  5. [BZOJ2653]middle 主席树+二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2042  Solved: 1123[Submit][Status][Disc ...

  6. BZOJ2653 middle 【二分 + 主席树】

    题目 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c ...

  7. [bzoj2653][middle] (二分 + 主席树)

    Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...

  8. Luogu2839 [国家集训队]middle 题解

    题目很好,考察对主席树的深入理解与灵活运用. 首先看看一般解决中位数的思路,我们二分一个 \(mid\),将区间中 \(\ge mid\) 的数置为 \(1\),小于的置为 \(-1\),然后求区间和 ...

  9. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

随机推荐

  1. Docker - 容器中的tomcat如何使用startup.sh启动

    网上大多介绍的catalina.sh启动,因为docker容器中,无法直接启动startup.sh. 解决方法: 编辑catalina.sh,找到 >> "$CATALINA_O ...

  2. Mac brew安装redis

    1.安装redis $ brew install redis Error:Failed to download resource "reds"  // 下载reds失败 不过不需要 ...

  3. vue2组件之间双向数据绑定问题

    最近在使用element-ui的dialog组件二次封装成独立组件使用时,子组件需要将关闭dialog状态返回给父组件,简单的说就是要实现父子组件之间的数据双向绑定问题. 大致代码如下: 1,父组件 ...

  4. 「日常训练」Equation(HDU-5937)

    题意与分析 时隔一个月之后来补题.说写掉的肯定会写掉. 题意是这样的:给1~9这些数字,每个数字有\(X_i\)个,问总共能凑成多少个不同的等式\(A+B=C\)(\(A,B,C\)均为1位,\(1+ ...

  5. 「日常训练」Brackets in Implications(Codeforces Round 306 Div.2 E)

    题意与分析 稍微复杂一些的思维题.反正这场全是思维题,就一道暴力水题(B).题解直接去看官方的,很详尽. 代码 #include <bits/stdc++.h> #define MP ma ...

  6. Struts2(九.利用layer组件实现图片显示功能)

    1.layer前端组件介绍 layer是一款口碑极佳的web弹层组件,她具备全方位的解决方案,致力于服务各个水平段的开发人员,您的页面会轻松地拥有丰富而友好的操作体验. http://sentsin. ...

  7. 子序列 (All in All,UVa10340)

    题目描述:算法竞赛入门经典习题3-9 题目思路:循环匹配 //没有按照原题的输入输出 #include <stdio.h> #include <string.h> #defin ...

  8. 在Arch上安装VSCode的方法

    首先去特硬去下载vscode的安装包 mkdir /tmp/vscode cd /tmp/vscode/ wget https://az764295.vo.msecnd.net/public/0.3. ...

  9. CodeForces 908C. New Year and Curling 解题报告 Java

    1. 思路 这题实际上是个几何问题——两个外相切的圆,由勾股定理,他们的纵坐标有以下的规律: 则有$$y_{n+1} = y_{n} + \sqrt{(2r)^2 - (x_{n} - x_{n+1} ...

  10. java鼠标操控小程序

    最近在做一个软工的屏幕监控软件,已经实现了屏幕图片的传输,但是没有鼠标,才发现键盘上的PtrScSysRq键所截到图是没有鼠标信息的.== 暂时只需实现鼠标的移动事件,用robot.mouseMove ...