[bzoj2653]middle

来自FallDream的博客,未经允许,请勿转载,谢谢


ditoly太强了 随便切  我被d飞了

-------------------------------

由n个数ai,每次询问,给定四个数a,b,c,d,求一个左端点在[a,b],右端点在[c,d]的子序列(原题这么写,但是实际上是子串),使得它的中位数最大。强制在线

n<=20000 q<=25000

题解:考虑二分一个答案,然后check一下是否能够取到。

怎么check呢?假设要check一个数X,那么我们把大等于X的数字看成1,小于的看成-1,如果存在一个子序列的和大等于0,那么这个数字就是合法的。

所以我们可以维护一棵线段树,直接把每一位看成1或者-1,维护前缀和数组的最大最小值,然后数字从小到大把线段树可持久化一下,每次一个数字从1变成-1就是把一段区间-2,这个我们通过标记永久化实现。

复杂度$qlog^{2}n$

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MN 20000
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define INF 2000000000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,m,last=0,num[10],a[MN+5],cnt=0,l[MN+5],rt[MN+5];
pa p[MN+5];

struct data{
    int mx,mn;
    data(int x=0):mx(x),mn(x){}
    data(int x,int y):mx(x),mn(y){}
    data operator*(const data&b){return data(max(mx,b.mx),min(mn,b.mn));} 
    data operator+(int y){return data(mx+y,mn+y);}
};
struct node{int l,r,val;data x;}T[MN*60+5];

inline int mark(int x,int k)
{
    int nx=++cnt;T[nx].l=T[x].l;T[nx].r=T[x].r;
    T[nx].x=T[x].x+k;T[nx].val=T[x].val+k;    
    return nx;
}

void pushdown(int x)
{
    T[x].l=mark(T[x].l,T[x].val);
    T[x].r=mark(T[x].r,T[x].val);
    T[x].val=0;
}

int ins(int x,int l,int r,int ad,int lt=0,int rt=n)
{
    if(l==lt&&rt==r){return mark(x,ad);}
    int nx=mark(x,0);pushdown(nx);
    int mid=lt+rt>>1;
    if(r<=mid) 
        T[nx].l=ins(T[nx].l,l,r,ad,lt,mid);
    else if(l>mid)
        T[nx].r=ins(T[nx].r,l,r,ad,mid+1,rt);
    else 
        T[nx].l=ins(T[nx].l,l,mid,ad,lt,mid),T[nx].r=ins(T[nx].r,mid+1,r,ad,mid+1,rt);
    T[nx].x=T[T[nx].l].x*T[T[nx].r].x;
    return nx;
}

int build(int l,int r)
{
    int x=++cnt,mid=l+r>>1;
    if(l==r) {T[x].x=data(l);return x;}
    T[x].l=build(l,mid);T[x].r=build(mid+1,r);
    T[x].x=T[T[x].l].x*T[T[x].r].x;
    return x;
}

data query(int x,int l,int r,int lt=0,int rt=n)
{
    if(l==lt&&rt==r) return T[x].x;
    int mid=lt+rt>>1;
    if(r<=mid) return query(T[x].l,l,r,lt,mid)+T[x].val;
    else if(l>mid) return query(T[x].r,l,r,mid+1,rt)+T[x].val;
    else return query(T[x].l,l,mid,lt,mid)*query(T[x].r,mid+1,r,mid+1,rt)+T[x].val;
}

int main()
{    
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) p[i]=mp(a[i],i);
    sort(p+1,p+n+1);rt[1]=build(0,n);
    for(int i=2;i<=n;i++)
        rt[i]=ins(rt[i-1],p[i-1].second,n,-2);
    m=read();
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=4;j++) num[j]=(read()+last)%n+1;
        sort(num+1,num+5);
        int a=num[1],b=num[2],c=num[3],d=num[4];
        int L=1,R=n,mid,ans=0;
        while(L<=R)
        {
            mid=L+R>>1;    
            if(query(rt[mid],c,d).mx-query(rt[mid],a-1,b-1).mn>=0) ans=mid,L=mid+1;
            else R=mid-1;
        }
        printf("%d\n",last=p[ans].first);
    }
    return 0;
}

 

posted @ 2017-04-10 21:53  FallDream  阅读(180)  评论(0编辑  收藏  举报