您的位置:首页 > 其它

[bzoj 2653] middle

2015-06-13 07:14 211 查看
陈老师的神题,先拜一下

求中位数用二分的方法很容易想到。

可以想到我们把二分到数x后,把小于x的定义为-1,大于等于x的定义为1,只要求出一个子序列和大于等于0就说明中位数大于等于x(题目中的n/2是向上取整的)

然而之后我并不知道怎么做


一般我们建立主席树都是按照数组下标顺序来建的,这题比较奇葩。

假设我们只需要查询中位数为x的时候,最大的子序列和是否大于等于0,会做吧——直接弄出新数组,想gss那样搞就行了

注意到将整个数组排序之后,二分到相邻的两个答案,新数组只会有几个位置不同,就是将若干个1改为-1,不拿发现改为-1后不会再变为1了,也就是说最多总共只有n个改变值。可以利用这个建主席树!

有了这个后我们只需要询问[a,b-1]的rmax + [b,c]的sum + [c+1,d]的lmax是否大于等于0即可。

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int Maxn = 2000005;
int a[Maxn], b[Maxn], T[Maxn];
int son[Maxn][2], q[4];
int st,n,m,Q,i,L,R,Mid,ans;
vector <int> e[Maxn];
struct Seg_Tr
{
int sum, lmax, rmax;
} Tree[Maxn];

Seg_Tr operator +(const Seg_Tr &a, const Seg_Tr &b)
{
Seg_Tr ret;
ret.sum = a.sum + b.sum;
ret.lmax = max(a.lmax, a.sum+b.lmax);
ret.rmax = max(b.rmax, b.sum+a.rmax);
return ret;
}

void init(int &p,int l,int r){
p = ++st;
Tree[p].sum = r-l+1;
Tree[p].lmax = r-l+1;
Tree[p].rmax = r-l+1;
if (l==r) return;
int mid = (l+r)>>1;
init(son[p][0],l,mid);
init(son[p][1],mid+1,r);
}

void ins(int &p,int q,int l,int r,int k,int L,int R){
if (L>R) {p=q; return;}
p = ++st;
if (l==r){
Tree[p].sum = -1;
Tree[p].lmax = 0;
Tree[p].rmax = 0;
return;
}
int mid = (l+r)>>1, t = L;
while (t<=R && e[k][t]<=mid) t++;
ins(son[p][0],son[q][0],l,mid,k,L,t-1);
ins(son[p][1],son[q][1],mid+1,r,k,t,R);
Tree[p] = Tree[son[p][0]] + Tree[son[p][1]];
}

Seg_Tr query(int p,int l,int r,int L,int R){
if (L>R || L>r || l>R) return (Seg_Tr){0,0,0};
if (L<=l && R>=r) return Tree[p];
int mid = (l+r)>>1;
return query(son[p][0],l,mid,L,R) + query(son[p][1],mid+1,r,L,R);
}

bool Judge(int x){
Seg_Tr LF = query(T[x],1,n,q[0],q[1]-1);
Seg_Tr MD = query(T[x],1,n,q[1],q[2]);
Seg_Tr RG = query(T[x],1,n,q[2]+1,q[3]);
return LF.rmax+MD.sum+RG.lmax >= 0;
}

int main(){
scanf("%d",&n);
for (i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b+1,b+n+1);
m = unique(b+1,b+n+1)-b-1;
for (i=1;i<=n;i++){
a[i] = lower_bound(b+1,b+m+1,a[i])-b;
e[a[i]].push_back(i);
}
init(T[1],1,n);
for (i=2;i<=m;i++)
ins(T[i],T[i-1],1,n,i-1,0,e[i-1].size()-1);

scanf("%d",&Q);
while (Q--){
scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]);
for (i=0;i<4;i++) q[i] = (q[i]+b[ans])%n+1;
sort(q,q+4);
L = 1; R = m;
while (L<=R){
int Mid = (L+R)>>1;
if (Judge(Mid)) ans = Mid, L = Mid+1;
else R = Mid-1;
}
printf("%d\n",b[ans]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: