bzoj 2653: middle (二分+主席树)
来源:互联网 发布:阿里云华东 编辑:程序博客网 时间:2024/06/18 07:13
2653: middle
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1289 Solved: 730
[Submit][Status][Discuss]
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
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
Source
每次先二分一个中位数,判断是否可行。
我们考虑如何判断该中位数数是否可行?将序列中的数比当前数小的赋值成-1,大的赋值成1,如果一段区间的和为0,那么该数就是区间的中位数。我们现在考虑[a,b],[c,d]的限制,如果[a,b]中右端连续一段的最大值+(b,c)的区间和+[c,d]中左端连续一段的最大值>=0的话,那么就能说明中位数>=当前二分到的数。
如何维护针对每次数的1,-1序列呢?将数从小到大排序,我们可以初始时令序列为全1的序列,当我们对于一个数建树的时候,我们只需要在前一个数序列的基础上将上一个数的位置改成-1即可。然后就行普通的线段数一样,维护区间总和,区间右端连续、左端连续一段的最大值即可。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 4000003 using namespace std; int a1[N],b[N],sz,n,m,root[N],q[10]; struct data{ int l,r,lx,rx,sum; }tr[N]; int cmp(int x,int y) { return a1[x]<a1[y]; } void update(int now) { int l=tr[now].l; int r=tr[now].r; tr[now].sum=tr[l].sum+tr[r].sum; tr[now].lx=max(tr[l].lx,tr[l].sum+tr[r].lx); tr[now].rx=max(tr[r].rx,tr[r].sum+tr[l].rx); } int build(int l,int r) { int now=++sz; tr[now].l=tr[now].r=tr[now].lx=tr[now].rx=tr[now].sum=0; if (l==r) { tr[now].sum=tr[now].lx=tr[now].rx=1; return now; } int mid=(l+r)/2; tr[now].l=build(l,mid); tr[now].r=build(mid+1,r); update(now); return now; } void insert(int &i,int l,int r,int pos,int v) { tr[++sz]=tr[i]; i=sz; if (l==r) { tr[i].sum=tr[i].lx=tr[i].rx=v; return; } int mid=(l+r)/2; if (pos<=mid) insert(tr[i].l,l,mid,pos,v); else insert(tr[i].r,mid+1,r,pos,v); update(i); //cout<<i<<" "<<l<<" "<<r<<" "<<tr[i].lx<<" "<<tr[i].rx<<" "<<tr[i].sum<<endl;} int query(int now,int l,int r,int ll,int rr) { if (ll>rr) return 0; if (ll<=l&&r<=rr) return tr[now].sum; int mid=(l+r)/2; int ans=0; if (ll<=mid) ans+=query(tr[now].l,l,mid,ll,rr); if (rr>mid) ans+=query(tr[now].r,mid+1,r,ll,rr); return ans; } int findl(int now,int l,int r,int ll,int rr) { if (ll>rr) return 0; if (ll<=l&&r<=rr) return tr[now].lx; int mid=(l+r)/2; int ans=-1000000000; if (ll<=mid) ans=max(ans,findl(tr[now].l,l,mid,ll,rr)); if (rr>mid){ int t=query(now,l,r,ll,mid); ans=max(ans,t+findl(tr[now].r,mid+1,r,ll,rr)); } return ans; } int findr(int now,int l,int r,int ll,int rr) { if (ll>rr) return 0; if (ll<=l&&r<=rr) return tr[now].rx; int mid=(l+r)/2; int ans=-1000000000; if (rr>mid) ans=max(ans,findr(tr[now].r,mid+1,r,ll,rr)); if (ll<=mid){ int t=query(now,l,r,mid+1,rr); ans=max(ans,t+findr(tr[now].l,l,mid,ll,rr)); } return ans; } bool pd(int now,int a,int b,int c,int d) { int val=0; val+=query(root[now],0,n-1,b+1,c-1); //cout<<val<<" "; val+=findr(root[now],0,n-1,a,b); //cout<<val<<" "; val+=findl(root[now],0,n-1,c,d); //cout<<val<<endl; return val>=0; } int solve(int a,int b,int c,int d) { int l=0; int r=n-1; int ans=0; while (l<=r){ int mid=(l+r)/2; if (pd(mid,a,b,c,d)) ans=mid,l=mid+1; else r=mid-1; } return ans; } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d",&n); for (int i=0;i<n;i++) scanf("%d",&a1[i]),b[i]=i; sort(b,b+n,cmp); root[0]=build(0,n-1); for (int i=1;i<n;i++) { root[i]=root[i-1],insert(root[i],0,n-1,b[i-1],-1); } int ans=0; sort(a1,a1+n); scanf("%d",&m); for (int i=1;i<=m;i++){ for (int j=1;j<=4;j++) scanf("%d",&q[j]),q[j]=(q[j]+ans)%n; sort(q+1,q+4+1); int a,b,c,d; a=q[1]; b=q[2]; c=q[3]; d=q[4]; //cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl; ans=solve(a,b,c,d); ans=a1[ans]; printf("%d\n",ans); } }
- Bzoj 2653 middle(二分+主席树)
- bzoj 2653: middle (二分+主席树)
- BZOJ 2653 middle 二分+主席树
- [主席树 二分答案] BZOJ 2653 middle
- BZOJ 2653: middle 主席树+二分
- bzoj 2653 middle 二分答案 主席树判定
- 【主席树】 BZOJ 2653 middle
- 【主席树】BZOJ 2653 middle
- BZOJ 2653: middle|主席树
- HYSBZ 2653middle(二分+主席树)
- [BZOJ2653]middle(二分+主席树)
- [BZOJ2653]middle(主席树+二分)
- bzoj2653 Middle 二分&主席树
- [主席树+二分] BZOJ2653: middle
- bzoj 2653(主席树+二分)
- bzoj 2653 二分+主席树
- [BZOJ]2653: middle 线段树合并+二分
- 【BZOJ 2653】middle 主席树好题推荐
- Docker基础
- 香港四大天王影帝情况(截止2016)
- LeetCode笔记:303. Range Sum Query - Immutable
- 警告"warning: type qualifiers ignored on function return type"
- webrtc编译好的国内包
- bzoj 2653: middle (二分+主席树)
- 进程组和组长进程
- ubuntu安装软件的管理
- js的闭包(二)——闭包的机理之我见
- 吃鸡腿
- Retrofit+RxJava完美封装(二)
- SDL_CDStop函数
- scrollview嵌套listview运行后最先显示出来的位置不在顶部而是下方问题
- C++中抽象类和接口的区别介绍