【BZOJ2653】middle 二分+可持久化线段树
【BZOJ2653】middle
Description
Input
Output
Q行依次给出询问的答案。
Sample Input
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0
271451044
271451044
969056313
Sample Output
HINT
0:n,Q<=100
1,...,5:n<=2000
0,...,19:n<=20000,Q<=25000
题解:好吧这题不看题解还真的很难想~
首先二分中位数还是挺好像的,但问题是怎么判断一个中位数是否可行。一个中位数mid可行的条件是序列中(≥mid的数的个数)≥(<mid的数的个数),也就是说,我们将比≥mid的数看成1,<mid的数看成-1,那么需要存在一段区间,使得区间和非负。这又和可持久化线段树有什么关系呢?
我们将所有数排序,然后令1-n的初值都是1,然后将n个数从小到大扔到可持久化线段树中去,并将对应位置变成-1,这样就很好的满足了所给条件。现在问题就是如何判断[a,b]-[c,d]中有没有符合条件的区间,只需要对线段树维护区间连续子段和,最大连续前缀子段和,最大后缀子段和,然后搞一搞就行了。(小白逛公园的简化)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=20010;
int n,m,maxx,minn,tot,ans;
struct sag
{
int ls,rs,sum,lm,rm,sm;
}s[maxn*1000];
struct node
{
int num,org;
}p[maxn];
int q[10],rt[maxn];
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int max(int a,int b,int c)
{
return max(max(a,b),c);
}
void pushup(int x)
{
s[x].lm=max(s[s[x].ls].lm,s[s[x].ls].sum+s[s[x].rs].lm,0);
s[x].rm=max(s[s[x].rs].rm,s[s[x].rs].sum+s[s[x].ls].rm,0);
s[x].sm=max(s[s[x].ls].sm,s[s[x].rs].sm,s[s[x].ls].rm+s[s[x].rs].lm);
s[x].sum=s[s[x].ls].sum+s[s[x].rs].sum;
}
void build(int l,int r,int &x)
{
if(!x) x=++tot;
if(l==r)
{
s[x].sum=s[x].sm=s[x].lm=s[x].rm=1;
return;
}
int mid=l+r>>1;
build(l,mid,s[x].ls),build(mid+1,r,s[x].rs);
pushup(x);
}
void insert(int x,int &y,int l,int r,int pos)
{
if(r<pos) return ;
y=++tot;
if(l==r)
{
s[y].sum=-1,s[y].lm=s[y].rm=s[y].sm=0;
return ;
}
int mid=l+r>>1;
if(pos<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos);
else s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos);
pushup(y);
}
bool cmp(node a,node b)
{
return a.num<b.num;
}
int qs(int l,int r,int x,int a,int b)
{
if(a>b) return 0;
if(a<=l&&r<=b) return s[x].sum;
int mid=l+r>>1;
if(b<=mid) return qs(l,mid,s[x].ls,a,b);
if(a>mid) return qs(mid+1,r,s[x].rs,a,b);
return qs(l,mid,s[x].ls,a,b)+qs(mid+1,r,s[x].rs,a,b);
}
int ql(int l,int r,int x,int a,int b)
{
if(a>b) return 0;
if(a<=l&&r<=b) return s[x].rm;
int mid=l+r>>1;
if(b<=mid) return ql(l,mid,s[x].ls,a,b);
if(a>mid) return ql(mid+1,r,s[x].rs,a,b);
return max(ql(l,mid,s[x].ls,a,b)+qs(mid+1,r,s[x].rs,a,b),ql(mid+1,r,s[x].rs,a,b));
}
int qr(int l,int r,int x,int a,int b)
{
if(a>b) return 0;
if(a<=l&&r<=b) return s[x].lm;
int mid=l+r>>1;
if(b<=mid) return qr(l,mid,s[x].ls,a,b);
if(a>mid) return qr(mid+1,r,s[x].rs,a,b);
return max(qr(mid+1,r,s[x].rs,a,b)+qs(l,mid,s[x].ls,a,b),qr(l,mid,s[x].ls,a,b));
}
int solve(int sta)
{
int a=ql(1,n,rt[sta-1],q[0],q[1]-1);
int b=qs(1,n,rt[sta-1],q[1],q[2]);
int c=qr(1,n,rt[sta-1],q[2]+1,q[3]);
if(a+b+c>=0) return 1;
return 0;
}
int main()
{
n=rd();
int i,j,l,r,mid;
for(i=1;i<=n;i++) p[i].num=rd(),p[i].org=i,maxx=max(maxx,p[i].num),minn=min(minn,p[i].num);
build(1,n,rt[0]);
sort(p+1,p+n+1,cmp);
for(i=1;i<=n;i++) insert(rt[i-1],rt[i],1,n,p[i].org);
m=rd();
for(i=1;i<=m;i++)
{
for(j=0;j<4;j++) q[j]=(rd()+ans)%n+1;
sort(q+0,q+4);
l=1,r=n+1;
while(l<r)
{
mid=l+r>>1;
if(solve(mid)) l=mid+1;
else r=mid;
}
ans=p[l-1].num;
printf("%d\n",ans);
}
return 0;
}
【BZOJ2653】middle 二分+可持久化线段树的更多相关文章
- BZOJ 4556(后缀数组+主席树求前驱后继+二分||后缀数组+二分+可持久化线段树)
换markdown写了.. 题意: 给你一个1e5的字符串,1e5组询问,求\([l_1,r_1]\)的所有子串与\([l_2,r_2]\)的lcp 思路: 首先可以发现答案是具有单调性的,我们考虑二 ...
- 【XSY2720】区间第k小 整体二分 可持久化线段树
题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n ...
- bzoj 2653 middle (可持久化线段树)
middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1981 Solved: 1097[Submit][Status][Discuss] D ...
- 【BZOJ-2653】middle 可持久化线段树 + 二分
2653: middle Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1298 Solved: 734[Submit][Status][Discu ...
- [BZOJ 2653] middle(可持久化线段树+二分答案)
[BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- 【bzoj2653】middle 可持久化线段树区间合并
题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...
- 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)
有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...
- 计蒜客 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 ...
随机推荐
- Webbrowser控件判断网页加载完毕的简单方法
一般情况下,当ReadyState属性变成READYSTATE_COMPLETE时,Webbrowser控件会通过触发DocumentCompleted事件来指示网页加载完毕.但当加载的网页包含fra ...
- DevExpress SpinEdit控件使用实例——删除ASPxSpinEdit右边的上下小箭头SpinButtons-ShowIncrementButtons
使用ASPxSpinEdit来添加数字类型的输入框: 默认情况下, SpinEdit通过点击右边的上下箭头来加减number,下面的代码是去掉上下箭头,内容居中显示,并将边框颜色置为白色: <d ...
- JiaThis™“分享到”侧栏代码
风格:迷你: 猜你喜欢: 开启 使用说明: 复制并粘贴下面的JS代码,放到您的网页,可以在<body>和</body>的之间网页的任意位置放置.如果您的网站使用的模板, ...
- MAC 通过brew安装软件
1.安装brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/instal ...
- SICP 1.23-1.26体会
1.23 代码修改非常easy, 关键是时间. 电脑上算了一下. 100000000下面全是0. 開始还以为代码写错了. 最后没办法, 用1e10 1e11来计算. 发现比 1e11 1e12快1.2 ...
- ajax实现json循环输出结果
$.post("bankInfo.php",{key:jee_server,uid:jee_uid},function(data) { var strs=JSON.stringif ...
- Brackets - 前端编辑器推荐
Brackets是一款基于web(html+css+js)开发的web前端编辑器.它有许多普通编辑器难以实现的功能,是web前端开发者的神器. 戳我去下载 其功能如下: 1.快速编辑 将光标定在颜色上 ...
- DataURL与File,Blob,canvas对象之间的互相转换的Javascript (未完)
canvas转换为dataURL (从canvas获取dataURL) var dataurl = canvas.toDataURL('image/png'); var dataurl2 = canv ...
- laravel的表单验证(下面有些信息未验证,转的)
后台写法: 1.1类的方法 $rules = [ 'email'=>'required|between:4,20', 'password'=>'required|between:6,20' ...
- 点滴积累【JS】---JS小功能(JS实现隐藏显示侧边栏,也就是分享栏的隐藏显示)
效果: 思路: 首先,利用计时器setInterval实现DIV的隐藏显示功能,然后在进行一个判断,之后在把要移动的相应距离进行一个参数传递,再根据参数判断出移动的方向也就是offsetLeft移动的 ...