题目描述

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

输入

第一行序列长度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]。  
输入保证满足条件。
第一行所谓“排过序”指的是从小到大排序!
n<=20000,Q<=25000

输出

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

样例输入

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

样例输出

271451044
271451044
969056313
 
  对于一个序列,如果序列有奇数个数,那么中位数是中间那个数,如果有偶数个数,那么中位数是中间两个中后面那个。如果要判断M是否为合法的中位数,就把序列中>=M的数权值设为1,<M的数权值设为-1,只要有一段区间的最大连续子段和>=0,那么M就是合法的。因此求一段区间的中位数可以二分中位数是什么,只要rmax(a,b-1)+sum(b,c)+lmax(c+1,d)大于零那么这个数就可能成为中位数(其中sum表示区间和,lmax表示区间从左端点开始最大连续子段和,rmax表示区间从右端点开始最大连续子段和)。对于每次二分答案要将线段树中小于答案的数权值设为-1,其他数权值设为1,求上述最大连续子段和。但如果每次二分答案都重新建树显然太慢了,因此可以用主席树,每个时刻i的主席树表示以第i个数为中位数时线段树的状态,第一个时刻将所有位置置为1,然后下一时刻将最小的数那个位置权值置为-1,以此类推。每次二分答案只要查询对应时刻的主席树就好了。
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
int n,m;
int sum[5000010];
int lmx[5000010];
int rmx[5000010];
int ls[5000010];
int rs[5000010];
int root[50010];
int a,b,c,d;
int cnt;
int ans;
int p[5];
struct node
{
int num;
int id;
}s[20010];
bool cmp(node a,node b)
{
return a.num<b.num;
}
void pushup(int rt)
{
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
lmx[rt]=max(lmx[ls[rt]],sum[ls[rt]]+lmx[rs[rt]]);
rmx[rt]=max(rmx[rs[rt]],sum[rs[rt]]+rmx[ls[rt]]);
}
int build(int l,int r)
{
int rt=++cnt;
if(l==r)
{
sum[rt]=1;
lmx[rt]=1;
rmx[rt]=1;
return rt;
}
int mid=(l+r)>>1;
ls[rt]=build(l,mid);
rs[rt]=build(mid+1,r);
pushup(rt);
return rt;
}
int updata(int pre,int l,int r,int k)
{
int rt=++cnt;
if(l==r)
{
sum[rt]=-1;
lmx[rt]=0;
rmx[rt]=0;
return rt;
}
ls[rt]=ls[pre];
rs[rt]=rs[pre];
int mid=(l+r)>>1;
if(k<=mid)
{
ls[rt]=updata(ls[pre],l,mid,k);
}
else
{
rs[rt]=updata(rs[pre],mid+1,r,k);
}
pushup(rt);
return rt;
}
int query(int rt,int l,int r,int L,int R)
{
if(L>R)
{
return 0;
}
if(L<=l&&r<=R)
{
return sum[rt];
}
int mid=(l+r)>>1;
if(L>mid)
{
return query(rs[rt],mid+1,r,L,R);
}
else if(R<=mid)
{
return query(ls[rt],l,mid,L,R);
}
return query(ls[rt],l,mid,L,R)+query(rs[rt],mid+1,r,L,R);
}
int findl(int rt,int l,int r,int L,int R)
{
if(L>R)
{
return 0;
}
if(L<=l&&r<=R)
{
return rmx[rt];
}
int mid=(l+r)>>1;
int res=0;
if(R>mid)
{
res=findl(rs[rt],mid+1,r,L,R);
}
if(L<=mid)
{
res=max(res,findl(ls[rt],l,mid,L,R)+query(rs[rt],mid+1,r,mid+1,R));
}
return res;
}
int findr(int rt,int l,int r,int L,int R)
{
if(L>R)
{
return 0;
}
if(L<=l&&r<=R)
{
return lmx[rt];
}
int mid=(l+r)>>1;
int res=0;
if(L<=mid)
{
res=findr(ls[rt],l,mid,L,R);
}
if(R>mid)
{
res=max(res,findr(rs[rt],mid+1,r,L,R)+query(ls[rt],l,mid,L,mid));
}
return res;
}
bool check(int x,int a,int b,int c,int d)
{
int res=0;
res+=query(root[x],1,n,b,c);
res+=findl(root[x],1,n,a,b-1);
res+=findr(root[x],1,n,c+1,d);
if(res>=0)
{
return true;
}
return false;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i].num);
s[i].id=i;
}
root[1]=build(1,n);
sort(s+1,s+1+n,cmp);
for(int i=2;i<=n;i++)
{
root[i]=root[i-1];
root[i]=updata(root[i],1,n,s[i-1].id);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
p[1]=(a+ans)%n;
p[2]=(b+ans)%n;
p[3]=(c+ans)%n;
p[4]=(d+ans)%n;
sort(p+1,p+5);
a=p[1]+1;
b=p[2]+1;
c=p[3]+1;
d=p[4]+1;
int l=1;
int r=n;
ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid,a,b,c,d))
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
ans=s[ans].num;
printf("%d\n",ans);
}
}

BZOJ2653middle——二分答案+可持久化线段树的更多相关文章

  1. bzoj 2653 二分答案+可持久化线段树

    首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和 ...

  2. BZOJ 2653 middle 二分答案+可持久化线段树

    题目大意:有一个序列,包含多次询问.询问区间左右端点在规定区间里移动所得到的最大中位数的值. 考虑对于每个询问,如何得到最优区间?枚举显然是超时的,只能考虑二分. 中位数的定义是在一个序列中,比中位数 ...

  3. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  4. 【BZOJ2653】middle 二分+可持久化线段树

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

  5. BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)

    换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...

  6. 【BZOJ-2653】middle 可持久化线段树 + 二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discu ...

  7. BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)

    BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...

  8. 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)

    有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...

  9. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

随机推荐

  1. SkylineGlobe 如何二次开发获取三维模型的BBOX和设置Tint属性

    测试模型类型选择TerrainModel和Feature两种,测试代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transiti ...

  2. CF11D A Simple Task 状压DP

    传送门 \(N \leq 19\)-- 不难想到一个状压:设\(f_{i,j,k}\)表示开头为\(i\).结尾为\(j\).经过的点数二进制下为\(k\)的简单路总数,贡献答案就看\(i,j\)之间 ...

  3. Luogu3209 HNOI2010 平面图判定 平面图、并查集

    传送门 题意:$T$组数据,每组数据给出一个$N$个点,$M$条边,并存在一个$N$元环的图,试判断其是否为一个可平面图(如果存在一种画法,使得该图与给出的图同构且边除了在顶点处以外互相不相交,则称其 ...

  4. 2091: [Poi2010]The Minima Game

    2091: [Poi2010]The Minima Game 链接 分析: 首先排序后,一定是选的连续的一段. f[i]表示前i个位置,先手-后手的最大得分. 那么考虑第i个位置是否选,如果选,先手选 ...

  5. linux下用户操作记录审计环境的部署记录

    通常,我们运维管理人员需要知道一台服务器上有哪些用户登录过,在服务器上执行了哪些命令,干了哪些事情,这就要求记录服务器上所用登录用户的操作信息,这对于安全维护来说很有必要.废话不多说了,下面直接记录做 ...

  6. Mysql优化系列(1)--Innodb重要参数优化

    1.简单介绍InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎.InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读.这些特色 ...

  7. Nginx报错: "Too many open files accept" 和 "could not build the server_names_hash"

    一.访问Nginx时,报错:"accept() failed (24: Too many open files)"原因时:nginx的连接数超过了系统设定的最大值造成的. 处理办法 ...

  8. Visual Studio2015安装过程以及单元测试

    安装环境: 安装版本: Visual Studio2015 安装过程: 因为我是在第一次老师安排的作业的时候感觉VC++6.0不如VS方便所以才装的Visual Studio2015,又安装了点插件, ...

  9. Atcoder C - Vacation ( DP )

    C - Vacation Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement Taro' ...

  10. shell脚本--cut命令与awk简单使用

    cut:对内容进行列切割 -d 后面的是分割符,表示用什么符号来分割符来分割列,分隔符使用引号括起来: -f后面跟着要选择的字段列,从1开始,表示第一列,如果要多列,可以用逗号分隔 : -c参数后面跟 ...