题目描述

一个长度为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. CF101D Castle 树形DP、贪心

    题目传送门 题意:给出一个有$N$个点的树,你最开始在$1$号点,经过第$i$条边需要花费$w_i$的时间.每条边只能被经过$2$次.求出到达除$1$号点外所有点的最早时间的最小平均值.$N \leq ...

  2. 创建Web API并使用

    昨晚有教一个网友在ASP.NET MVC里,创建Web API和在MVC视图中应用此API. 可以在ASP.NET MVC中,创建程序的model: namespace Insus.NET.Model ...

  3. 转:判断js中的数据类型的几种方法

    判断js中的数据类型有一下几种方法:typeof.instanceof. constructor. prototype. $.type()/jquery.type(),接下来主要比较一下这几种方法的异 ...

  4. Codeforces Edu Round 63(Rated for Div. 2)

    感觉现在Edu场比以前的难多了…… A: 温暖人心 /* basic header */ #include <iostream> #include <cstdio> #incl ...

  5. Codeforces 996E Leaving the Bar (随机化)

    题目连接:Leaving the Bar 题意:给你n个向量,你可以加这个向量或减这个向量,使得这些向量之和的长度小于1.5e6. 题解: 按照正常的贪心方法,最后的结果有可能大于1.5e6 .这里我 ...

  6. eclipse取消自动输入提示

    在设置Eclipse自动提示后,按a-z都会显示提示,但是我们需要键入Enter才会输入,而默认的所有都键入,非常弱智,可采用下面方法设置. 1,先找到相关的插件: window -> show ...

  7. Python-习题-11

    1,内容回顾列表:增 append insert extend 删 remove pop clear del 改 li[索引] = '被修改的内容' li[切片]:'被修改的内容' 查 for循环 r ...

  8. Linux内核第三节 20135332武西垚

    总结部分: Linux内核源代码: Arch 支持不同cpu的源代码:主要关注x86 Init   内核启动的相关代码:主要关注main.c,整个Linux内核启动代码start_kernel函数 K ...

  9. android开发之图表

    在这里使用的插件为Mpchart,只以折线图为例.首先需要导入

  10. POI (Apache POI)

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 基本功能 编辑 结构: HSSF - 提供读写Mi ...