BZOJ2653: middle

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2653

二分答案。对离散化后的每一个数都建立一棵区间线段树(然后可持久化掉),对于大于等于它的数设为1,否则设为-1 。

然后对于询问只要找(a,b)之间的右起最大和+(c,d)之间的左起最大和+(b+1,c-1)之间的总和≥0就满足否则不满足。

(注意一下如何维护左起最大和,右起最大和。。

#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 50050
#define ll long long
using namespace std;
struct data{int id,x;
}a[maxn];
int sum[maxn*20],lsum[maxn*20],rsum[maxn*20],ls[maxn*20],rs[maxn*20];
int root[maxn];
int n,m,q[5],cnt,ans;
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
bool cmp(data a,data b){
    return a.x<b.x;
}
void up(int i){
    if (i==0) return;
    sum[i]=sum[ls[i]]+sum[rs[i]];
    lsum[i]=max(lsum[ls[i]],sum[ls[i]]+lsum[rs[i]]);
    rsum[i]=max(rsum[rs[i]],sum[rs[i]]+rsum[ls[i]]);
}
void build(int &i,int l,int r){
    i=++cnt;
    int mid=(l+r)/2;
    if (l==r){
        sum[i]=lsum[i]=rsum[i]=1; return;
    }
    build(ls[i],l,mid); build(rs[i],mid+1,r);
    up(i);
}
void add(int l,int r,int x,int &y,int val){
    y=++cnt;
    if (l==r) {sum[y]=lsum[y]=rsum[y]=-1; return;}
    int mid=(l+r)/2;
    ls[y]=ls[x]; rs[y]=rs[x];
    if (val<=mid) add(l,mid,ls[x],ls[y],val);
    else add(mid+1,r,rs[x],rs[y],val);
    up(y);
}
int qall(int i,int l,int r,int tl,int tr){
    if (tl==l&&r==tr) return sum[i];
    int mid=(l+r)/2;
    if (tr<=mid) return qall(ls[i],l,mid,tl,tr);
    else if (tl>mid) return qall(rs[i],mid+1,r,tl,tr);
    else return qall(ls[i],l,mid,tl,mid)+qall(rs[i],mid+1,r,mid+1,tr);
}
int ql(int i,int l,int r,int tl,int tr){
    if (tl==l&&r==tr) return lsum[i];
    int mid=(l+r)/2;
    if (tr<=mid) return ql(ls[i],l,mid,tl,tr);
    else if (tl>mid) return ql(rs[i],mid+1,r,tl,tr);
    else return max(ql(ls[i],l,mid,tl,mid),qall(ls[i],l,mid,tl,mid)+ql(rs[i],mid+1,r,mid+1,tr));
} 
int qr(int i,int l,int r,int tl,int tr){
    if (tl==l&&r==tr) return rsum[i];
    int mid=(l+r)/2;
    if (tr<=mid) return qr(ls[i],l,mid,tl,tr);
    else if (tl>mid) return qr(rs[i],mid+1,r,tl,tr);
    else return max(qall(rs[i],mid+1,r,mid+1,tr)+qr(ls[i],l,mid,tl,mid),qr(rs[i],mid+1,r,mid+1,tr));
}
bool jud(int a,int b,int c,int d,int x){
    int ans=0;
    ans=qr(root[x],0,n-1,a,b);
    ans+=ql(root[x],0,n-1,c,d);
    if (b+1<c) ans+=qall(root[x],0,n-1,b+1,c-1);
    if (ans>=0) return 1;
    return 0;  
}
int main(){
    n=read();
    rep(i,0,n-1) a[i].x=read(),a[i].id=i;
    sort(a,a+n,cmp);
    build(root[0],0,n-1);
    rep(i,1,n-1) add(0,n-1,root[i-1],root[i],a[i-1].id);
    m=read(); ans=0;
    rep(i,1,m){
        rep(j,1,4) q[j]=(read()+ans)%n; sort(q+1,q+1+4); 
        int rec=0;
        int l=0,r=n-1;
        while (l<=r){
            int mid=(l+r)/2;
            if (jud(q[1],q[2],q[3],q[4],mid)) {rec=mid; l=mid+1;}
            else r=mid-1;
        }
        ans=a[rec].x;
        printf("%d\n",ans); 
        
    }
    return 0;
}

 

posted on 2015-12-22 12:50  ctlchild  阅读(175)  评论(0编辑  收藏  举报

导航