zoukankan      html  css  js  c++  java
  • 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
    ",pre=erfen());
        }
        return 0;
    }
  • 相关阅读:
    codeforces 363B
    hdu 1075 字典树
    D
    C A Simple Job
    Washing Plates 贪心
    HDU 4143 A Simple Problem 分解因式
    ACdream 1236 Burning Bridges 割边 + 去重边
    E. Beautiful Subarrays 字典树
    反素数 -- 数学
    Codeforces Beta Round #79 (Div. 1 Only) B. Buses 树状数组
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8167752.html
Copyright © 2011-2022 走看看