bzoj2653:middle

思路:首先容易想到二分答案,但如何去check呢,对于一段区间[l,r],把所有小于答案的都赋值为-1,大于等于它的都赋值为1,然后求左端点在[a,b],右端点在[c,d]的最大子串和即可(也就是区间[a,b]的最大右子串和加上(b,c)的子串和加上区间[c,d]的最大左子串和)这样既可,用个线段树维护一下,每次暴力重建,单次询问的复杂度是完全可以承受的,但如果多次询问时间复杂度将是n^2logn,复杂度将会爆炸,因此不能每次都暴力重建,然而能作为答案的只有n个元素,也就是说线段树只可能有n种形态,不妨利用可持久化线段树先预处理出询问a[i]时的线段树的形态,这样复杂度就能少一个n,也就是nlogn的复杂度是完全可以通过本题的。至于怎么预处理,先排序,然后在预处理以a[i]为答案的线段树时显然a[i-1]是要小于a[i]的,于是就在前一棵树的基础上把a[i-1]位置上的数改为-1,新建一个root即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 20005
 
int n,q,ans;
int t[4],a[maxn];
 
struct node{
    int val,pos;
    bool operator <(const node &a)const{return val<a.val;}
}v[maxn];
bool cmp(node a,node b){return a.pos<b.pos;}
 
int read(){
    int x=0;int f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
 
struct functional_segment_tree{
    int treedeg,root[maxn];
    struct treenode{
        int sum,lmax,rmax,ls,rs;
        treenode(){}
        treenode(int a,int b,int c,int d,int e){sum=a,lmax=b,rmax=c,ls=d,rs=e;}
    }tree[20*maxn];
    treenode merge(treenode a,treenode b){
        treenode ans=treenode(0,0,0,0,0);
        ans.sum=a.sum+b.sum;
        ans.lmax=max(a.lmax,a.sum+b.lmax);
        ans.rmax=max(b.rmax,b.sum+a.rmax);
        return ans;
    }
    void update(int p){
        int ls=tree[p].ls,rs=tree[p].rs;
        tree[p]=merge(tree[ls],tree[rs]);
        tree[p].ls=ls,tree[p].rs=rs;
    }
    void build(int &p,int l,int r,int val){
        p=++treedeg;int mid=(l+r)>>1;
        if (l==r){tree[p].lmax=tree[p].rmax=tree[p].sum=val;return;}
        build(tree[p].ls,l,mid,val),build(tree[p].rs,mid+1,r,val);
        update(p);
    }
    void change(int k,int &p,int l,int r,int pos,int val){
        p=++treedeg;
        if (l==r){tree[p].lmax=tree[p].rmax=tree[p].sum=val;return;}
        int mid=(l+r)>>1;
        if (pos<=mid) tree[p].rs=tree[k].rs,change(tree[k].ls,tree[p].ls,l,mid,pos,val);
        else tree[p].ls=tree[k].ls,change(tree[k].rs,tree[p].rs,mid+1,r,pos,val);
        update(p);
    }
    treenode query(int p,int l,int r,int x,int y){
        if (y<x) return treenode(0,0,0,0,0);
        if (x<=l&&r<=y) return tree[p];
        int mid=(l+r)>>1;treenode ans=treenode(0,0,0,0,0);bool flag=0;
        if (x<=mid) ans=query(tree[p].ls,l,mid,x,y),flag=1;
        if (y>mid){
            if (flag) ans=merge(ans,query(tree[p].rs,mid+1,r,x,y));
            else ans=query(tree[p].rs,mid+1,r,x,y);
        }
        return ans;
    }
}T;
 
bool check(int x){
    int a=T.query(T.root[x],0,n-1,t[0],t[1]).rmax;
    int b=T.query(T.root[x],0,n-1,t[1]+1,t[2]-1).sum;
    int c=T.query(T.root[x],0,n-1,t[2],t[3]).lmax;
    return a+b+c>=0;
}
 
int main(){
    n=read();
    for (int i=0;i<n;i++) a[i]=read(),v[i].val=a[i],v[i].pos=i;
    sort(v,v+n),T.build(T.root[0],0,n-1,1);
    for (int i=1;i<n;i++) T.change(T.root[i-1],T.root[i],0,n-1,v[i-1].pos,-1);
    q=read();
    while (q--){
        for (int i=0;i<4;i++) t[i]=(read()+ans)%n;sort(t,t+4);
        int l=0,r=n-1;
        while (l<r){
            int mid=(l+r)>>1;
            if (check(mid+1)) l=mid+1;
            else r=mid;
        }
        printf("%d\n",ans=v[l].val);
    }
    return 0;
}

 

posted @ 2016-10-28 14:23  DUXT  阅读(132)  评论(0编辑  收藏  举报