bzoj 2653 二分答案+可持久化线段树

  首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和加上[r1,l2]的区间和加上[l2,r2]的最大左区间和大于等于0,那么最大的中位数一定大于等于x。因为这个区间中大于等于x的数量超过了一半,那么我们可以二分答案,然后判断最大的合法(见上文)区间和是否大于等于0。

  那么对于每个我们二分的值的区间-1,1情况我们不能建立n颗线段树,我们可以建立可持久化线段树来维护这个,最开始的初始值都为1,设rot[x]为二分的值为x的时候区间的1,-1情况的线段树,可以由rot[x-1]这颗线段树继承过来。

  反思:之前写的可持久化线段树都是建立的权值线段树,这次是用线段树维护区间值的,而且之前对于rot[x]只会有一次插入,这道题的rot[x]可能会有多次插入,在这里纠结了半天。还有我就是最后输出的是adr[ans],但是前面强制在线的时候我加的是ans,忘了改了= =。

/**************************************************************
    Problem: 2653
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:2012 ms
    Memory:18196 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 50010
 
using namespace std;
 
struct rec {
    int key,ans,num;
    rec() {
        key=ans=num=0;
    }
}a[maxn];
 
struct segment {
    int left,right,maxr,maxl,sum;
    int son[2];
    segment() {
        left=right=maxr=maxl=sum=0;
        memset(son,0,sizeof son);
    }
}t[12*maxn];
 
int n,m,tot;
int rot[maxn],adr[maxn];
 
bool cmp1(rec x,rec y) {
    return x.ans<y.ans;
}
 
bool cmp2(rec x,rec y) {
    return x.num<y.num;
}
 
void update(int x) {
    t[x].sum=t[t[x].son[0]].sum+t[t[x].son[1]].sum;
    t[x].maxl=max(t[t[x].son[0]].sum+t[t[x].son[1]].maxl,t[t[x].son[0]].maxl);
    t[x].maxr=max(t[t[x].son[1]].sum+t[t[x].son[0]].maxr,t[t[x].son[1]].maxr);
}
 
void build(int &x,int l,int r) {
    if (!x) x=++tot;
    t[x].left=l; t[x].right=r;
    if (l==r) {
        t[x].sum=t[x].maxl=t[x].maxr=1;
        return ;
    }
    int mid=t[x].left+t[x].right>>1;
    build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);
    update(x);
}
 
void insert(int &x,int rot,int y) {
    if (!x) x=++tot;
    t[x].left=t[rot].left; t[x].right=t[rot].right;
    if (t[x].left==t[x].right) {
        t[x].sum=t[x].maxl=t[x].maxr=-1;
        return ;
    }
    int mid=t[x].left+t[x].right>>1;
    if (y>mid) {
        if (!t[x].son[0]) t[x].son[0]=t[rot].son[0];
        if (t[x].son[1]==t[rot].son[1]) t[x].son[1]=0;
        insert(t[x].son[1],t[rot].son[1],y);
    } else {
        if (!t[x].son[1]) t[x].son[1]=t[rot].son[1];
        if (t[x].son[0]==t[rot].son[0]) t[x].son[0]=0;
        insert(t[x].son[0],t[rot].son[0],y);
    }
    update(x);
}
 
segment combine(segment x,segment y) {
    segment ans;
    ans.sum=x.sum+y.sum;
    ans.maxl=max(x.sum+y.maxl,x.maxl);
    ans.maxr=max(y.sum+x.maxr,y.maxr);
    return ans;
}
 
segment query(int x,int l,int r) {
    if ((t[x].left==l)&&(t[x].right==r)) return t[x];
    int mid=t[x].left+t[x].right>>1;
    if (l>mid) return query(t[x].son[1],l,r); else
    if (r<=mid) return query(t[x].son[0],l,r); else
        return combine(query(t[x].son[0],l,mid),query(t[x].son[1],mid+1,r));
}
 
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[a[i].num=i].ans);
    sort(a+1,a+1+n,cmp1);
    int sum=1,cur=a[1].ans; adr[1]=a[1].ans;
    for (int i=1;i<=n;i++) if (a[i].ans==cur) a[i].key=sum; else a[i].key=++sum,adr[sum]=cur=a[i].ans;
    //sort(a+1,a+1+n,cmp2);
    //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("\n");
    build(rot[0],1,n);
    for (int i=1;i<=n;i++) insert(rot[a[i].key],rot[a[i].key-1],a[i].num);
    //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d %d\n",i,t[i].left,t[i].right,t[i].son[0],t[i].son[1],t[i].maxl,t[i].maxr);
    //for (int i=1;i<=n;i++) printf("%d ",adr[i]); printf("\n");
    scanf("%d",&m);
    int ans=0;
    while (m--) {
        int ask[5]; for (int i=1;i<=4;i++) scanf("%d",&ask[i]);
        for (int i=1;i<=4;i++) ask[i]=(ask[i]+adr[ans])%n+1;
        ans=0;
        sort(ask+1,ask+5);
        int l=1,r=n;
        while (l<=r) {
            int mid=l+r>>1,TOT=0;
            //printf("%d %d %d\n",l,r,a[mid].key);
            //printf("%d %d\n",l,r);
            segment a1=query(rot[a[mid].key-1],ask[1],ask[2]),a2=query(rot[a[mid].key-1],ask[3],ask[4]);
            if (ask[2]+1<=ask[3]-1) TOT=query(rot[a[mid].key-1],ask[2]+1,ask[3]-1).sum; 
            //printf("%d\n",TOT);
            TOT+=a1.maxr+a2.maxl; //printf("%d\n",TOT);
            //printf("%d\n",a1.maxr);
            if (TOT>=0) ans=a[mid].key,l=mid+1; else r=mid-1;
        }
        printf("%d\n",adr[ans]);
    }
    return 0;
}

 

posted on 2014-04-18 14:09  BLADEVIL  阅读(543)  评论(0编辑  收藏  举报