zoukankan      html  css  js  c++  java
  • 题解「Luogu2839 [国家集训队]middle」

    题面

    给一个序列 (s) ,回答 (Q) 个这样的询问:(s) 的左端点在 ([a,b]) 中,右端点在 ([c,d]) 中的子区间的最大中位数。

    题解

    首先要知道中位数怎么求:

    二分出一个 (mid) ,判断中位数 (m)(mid) 的大小关系。将询问区间 ([l,r]) 内所有 (s_i < mid) 赋值为 (-1)(s_igeq mid) 赋值为 (1) ,令 (sum=sum_{i=l}^rs_i) 分类讨论:

    • (sum geq 0) ,则 (m geq mid)
    • (sum<0) ,则 (m<mid)

    但是由于本题询问的区间不固定,上面的做法就需要改动。

    题目中要求 (m) 最大,所以对于一个值 (mid) ,我们要让 (sum) 尽量大,而区间 ([b+1,c-1])(sum) 是一定的,所以等价于区间 ([a,b],[c,d])(sum) 尽量大,这相当于求区间 ([a,b]) 和最大的后缀与区间 ([c,d]) 和最大的前缀(这里的前缀后缀长度都不为 (0) )。

    然后就有一个做法了:对于离散化后中位数可能取到的每一个值开一棵线段树,维护区间和 (sum) 、最大前缀和 (lsum) 、最大后缀和 (rsum) 。但是这样空间复杂度有 (O(n^2 { m{log}}n)) ,显然爆炸。

    不难发现值 (x) 对应的线段树与值 (x+1) 对应的线段树差别不大,也就是说我们记录了很多重复信息。显然,由 (x)(x+1) ,只有原序列中值为 (x) 的数对应的值由 (1) 变为了 (-1) ,这里就可以用一个类似主席树的东西继承值 (x) 对应的线段树上的信息。


    ( ext{vector}) 记录每个值的出现位置,每次以上一次修改为模板进行修改。

    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #define maxn 20005
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    
    template <typename T>
    inline T read()
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    int n,m,Q;
    int A[maxn],B[maxn];
    std::vector<int> P[maxn];
    int rt[maxn];
    
    struct Segment_Tree
    {
        struct node
        {
            int sum,lsum,rsum;
            node(int x=0){sum=lsum=rsum=x;}
            inline node operator + (const node &T)const
            {
                node res;
                res.sum=sum+T.sum;
                res.lsum=max(lsum,sum+T.lsum);
                res.rsum=max(T.rsum,T.sum+rsum);
                return res;
            }
        }tree[maxn<<5];
        int tot,ch[maxn<<5][2];
        inline int build(int l,int r,int d)
        {
            int p=++tot;
            if(l==r) {tree[p]=node(A[l]>=d?1:-1);return p;}
            int mid=(l+r)>>1;
            ch[p][0]=build(l,mid,d);
            ch[p][1]=build(mid+1,r,d);
            tree[p]=tree[ch[p][0]]+tree[ch[p][1]];
            return p;
        }
        inline int update(int l,int r,int pos,int tmp)
        {
            int p=++tot;
            tree[p]=tree[tmp];
            ch[p][0]=ch[tmp][0];ch[p][1]=ch[tmp][1];
            if(l==r) {tree[p]=node(-1);return p;}
            int mid=(l+r)>>1;
            if(pos<=mid)
                ch[p][0]=update(l,mid,pos,ch[tmp][0]);
            else
                ch[p][1]=update(mid+1,r,pos,ch[tmp][1]);
            tree[p]=tree[ch[p][0]]+tree[ch[p][1]];
            return p;
        }
        inline node query(int p,int l,int r,int L,int R)
        {
            if(L<=l&&r<=R) return tree[p];
            int mid=(l+r)>>1;
            if(R<=mid) return query(ch[p][0],l,mid,L,R);
            else if(L>mid) return query(ch[p][1],mid+1,r,L,R);
            else return query(ch[p][0],l,mid,L,R)+query(ch[p][1],mid+1,r,L,R);
        }
    }st;
    
    int a,b,c,d;
    
    inline int check(int mid)
    {
        int res=0;
        if(b+1<=c-1) res+=st.query(rt[mid],1,n,b+1,c-1).sum;
        res+=st.query(rt[mid],1,n,a,b).rsum;
        res+=st.query(rt[mid],1,n,c,d).lsum;
        return res;
    }
    
    int main()
    {
        // freopen("P2839.in","r",stdin);
        n=read<int >();
        for(int i=1;i<=n;++i)
            A[i]=B[i]=read<int >();
        sort(B+1,B+n+1);
        m=unique(B+1,B+n+1)-B-1;
        for(int i=1;i<=n;++i)
        {
            A[i]=lower_bound(B+1,B+m+1,A[i])-B;
            P[A[i]].push_back(i);
        }
        rt[1]=st.build(1,n,1);
        for(int i=2;i<=m;++i)
        {
            rt[i]=rt[i-1];
            for(vector<int>::iterator it=P[i-1].begin();it!=P[i-1].end();++it)
                rt[i]=st.update(1,n,*it,rt[i]);
        }
        int x=0,q[4];
        Q=read<int >();
        while(Q--)
        {
            q[0]=(read<int >()+x)%n+1,q[1]=(read<int >()+x)%n+1;
    		q[2]=(read<int >()+x)%n+1,q[3]=(read<int >()+x)%n+1;
    		sort(q,q+4);
    		a=q[0],b=q[1],c=q[2],d=q[3];
            int l=1,r=m,res=-1;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(check(mid)>=0) res=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d
    ",x=B[res]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    EasyNetQ使用(八)【对延迟消息插件的支持,自动订阅者】
    EasyNetQ使用(七)【发布者确认 ,用Future Publish发布预定中事件 】
    EasyNetQ使用(六)【多态发布和订阅,消息版本控制】
    EasyNetQ使用(五)【基于主题的路由,控制队列名称】
    EasyNetQ使用(四)【Request与Response,Send与Receive】
    可伸缩系统的架构经验
    Stack Exchange 的架构
    Quora使用到的技术
    Digg工程师讲述Digg背后的技术
    由12306.cn谈谈网站性能技术
  • 原文地址:https://www.cnblogs.com/syc233/p/13559985.html
Copyright © 2011-2022 走看看