BZOJ2653:middle——题解

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

Description

一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

Input

第一行序列长度n。接下来n行按顺序给出a中的数。
接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
x(如果这是第一个询问则x=0)。
令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的
要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
输入保证满足条件。

Output

Q行依次给出询问的答案。

Sample Input

5
170337785
271451044
22430280
969056313
206452321
3
3 1 0 2
2 3 1 4
3 1 4 0

Sample Output

271451044
271451044
969056313

——————————————————————————

debug真爽……一会再讲我神奇的debug经历。

(因为参照代码太多了所以就不一一贴了)

我们考虑如何求一个数比中位数大还是小。

方法很简单:将小于该数的数一律变成-1,大于等于的变为1,求和,如果和>=0即*可能为*这个数。

也就是说,我们可以用这个方法二分答案来求得中位数。

那么我们对于一组询问a,b,c,d,判断x与中位数的大小关系,就可以是求最大子序列和的过程了。

那么我们按照元素下标建线段树,并且存储每个区间的最大左/右连续和,,每个区间的和。

那么答案就是(ab最大右连续和)+(bc和)+(cd最大左连续和)。

但是我们不可能为每一组询问重新开一棵线段树,所以我们需要一种*预处理*所有可能的线段树的方法。

于是我们想到了主席树。

我们先对数列排序,这样假设我们中位数下标(以下都是排序后的新下标)为x,则显然0~x-1都是-1,而x~n-1都是1

那么我们的建树过程无非就是第一棵树全是1,而后的树对于前面的树的值都更新为-1就可以了。

(看着复杂,代码也复杂,debug1h一无所获,最后我精简代码发现我i和j搞反了……)

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int N=20010;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct tree{
    int l,r,sum,lx,rx;
}tr[N*20];
struct num{
    int v,p;
}a[N];
int rt[N],n,m,q,pool,p[4];
bool cmp(num f,num s){return f.v<s.v;}
inline void update(int x){
    tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum;
    tr[x].lx=max(tr[tr[x].l].lx,tr[tr[x].l].sum+tr[tr[x].r].lx);
    tr[x].rx=max(tr[tr[x].r].rx,tr[tr[x].r].sum+tr[tr[x].l].rx);
    return;
}
inline void build(int &x,int l,int r){
    x=++pool;
    if(l==r){
        tr[x].sum=tr[x].lx=tr[x].rx=1;
        return;
    }
    int mid=(l+r)>>1;
    build(tr[x].l,l,mid);
    build(tr[x].r,mid+1,r);
    update(x);
    return;
}
inline void insert(int y,int &x,int l,int r,int p,int v){
    tr[x=++pool]=tr[y];
    if(l==r){
        tr[x].sum=tr[x].lx=tr[x].rx=v;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p,v);
    else insert(tr[y].r,tr[x].r,mid+1,r,p,v);
    update(x);
    return;
}
inline int query_all(int k,int l,int r,int l1,int r1){
    if(l==l1&&r==r1)return tr[k].sum;
    int mid=(l+r)>>1;
    if(r1<=mid) return query_all(tr[k].l,l,mid,l1,r1);  
    else if(l1>mid) return query_all(tr[k].r,mid+1,r,l1,r1);
    else return query_all(tr[k].l,l,mid,l1,mid)+query_all(tr[k].r,mid+1,r,mid+1,r1);
}
inline int query_l(int k,int l,int r,int l1,int r1){
    if(l==l1&&r==r1)return tr[k].lx;
    int mid=(l+r)>>1;
    if(r1<=mid) return query_l(tr[k].l,l,mid,l1,r1);  
    else if(l1>mid) return query_l(tr[k].r,mid+1,r,l1,r1);
    else return max(query_l(tr[k].l,l,mid,l1,mid),query_all(tr[k].l,l,mid,l1,mid)+query_l(tr[k].r,mid+1,r,mid+1,r1));
}
inline int query_r(int k,int l,int r,int l1,int r1){
    if(l==l1&&r==r1)return tr[k].rx;
    int mid=(l+r)>>1;
    if(r1<=mid) return query_r(tr[k].l,l,mid,l1,r1);  
    else if(l1>mid) return query_r(tr[k].r,mid+1,r,l1,r1);
    else return max(query_r(tr[k].r,mid+1,r,mid+1,r1),query_all(tr[k].r,mid+1,r,mid+1,r1)+query_r(tr[k].l,l,mid,l1,mid));
}
bool pan(int k){
    int sum=0;
    if(p[1]+1<p[2])sum+=query_all(rt[k],0,n-1,p[1]+1,p[2]-1);
    sum+=query_r(rt[k],0,n-1,p[0],p[1]);
    sum+=query_l(rt[k],0,n-1,p[2],p[3]);
    return sum>=0;
}
int erfen(){
    int l=0,r=n-1,ans;
    while(l<=r){
        int mid=(l+r)>>1;
        if(pan(mid)){
            ans=a[mid].v;
            l=mid+1;
        }else r=mid-1;
    }
    return ans;
}
int main(){
    n=read();
    for(int i=0;i<n;i++){
        a[i].v=read();
        a[i].p=i;
    }
    sort(a,a+n,cmp);
    build(rt[0],0,n-1);
    for(int i=1;i<n;i++)insert(rt[i-1],rt[i],0,n-1,a[i-1].p,-1);
    q=read();
    int pre=0;
    for(int i=1;i<=q;i++){
        for(int j=0;j<4;j++)p[j]=(read()+pre)%n;
        sort(p,p+4);
        printf("%d\n",pre=erfen());
    }
    return 0;
}

 

posted @ 2018-01-01 16:09  luyouqi233  阅读(232)  评论(0编辑  收藏  举报