Luogu2839 middle

Description

给定一个数列,然后给定启示区间 ([a,b]) 和终止区间 ([c,d])

([l,r],lin[a,b],rin [c,d]) 的最大中位数

(nle 20000)

Solution

神仙思路

首先二分中位数

大于的是 (1),小于的是 (-1)

然后变成了必然取 ([b+1,c-1])([a,b]) 的最大后缀和 ([c,d]) 的最大前缀的问题

然后这步真的神仙:

对于所有的二分的mid维护线段树求 (lmax,rmax)

(这里是对值域操作)

开线段树是不太能够空间的,那么改成主席树

每次更改的时候直接在上一棵树上改改就行了(这里有点点细节)

Code

#include<bits/stdc++.h>
using namespace std;
#define reg register
namespace yspm{
    inline int read()
    {
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k=='-') f=-1;
        while(isdigit(k)) res=res*10+k-'0',k=getchar();
        return res*f;
    }
    const int N=2e4+10,M=N*60;
    int lans,q[5],a[N],b[N],n,m;
    vector<int> g[N];
    struct node{
        int sum,lm,rm;
    };
    inline node upd(node a,node b)
    {
        node res; res.sum=a.sum+b.sum; 
        res.lm=max(a.lm,max(a.sum+b.lm,res.sum));
        res.rm=max(a.rm+b.sum,max(b.rm,res.sum));
        return res;
    }
    int ls[M],lm[M],rm[M],rs[M],rt[N],sum[M],tot;
    inline void push_up(int p)
    {
        sum[p]=sum[ls[p]]+sum[rs[p]];
        rm[p]=max(rm[rs[p]],max(rm[ls[p]]+sum[rs[p]],sum[p]));
        lm[p]=max(lm[ls[p]],max(lm[rs[p]]+sum[ls[p]],sum[p]));
        return ;
    }
    inline void update(int &p,int pre,int l,int r,int pos,int val,bool fl)
    {
        if(!fl) p=++tot,ls[p]=ls[pre],rs[p]=rs[pre];
        if(l==r) return rm[p]=lm[p]=sum[p]=val,void();
        int mid=(l+r)>>1; 
        if(pos<=mid) 
        {
            if(ls[p]==ls[pre]) update(ls[p],ls[pre],l,mid,pos,val,0);
            else update(ls[p],ls[pre],l,mid,pos,val,1);
        }   
        else 
        {
            if(rs[p]==rs[pre]) update(rs[p],rs[pre],mid+1,r,pos,val,0);
            else update(rs[p],rs[pre],mid+1,r,pos,val,1);
        }return push_up(p);
    }
    inline node findrm(int p,int st,int ed,int l,int r)
    {
        if(l<=st&&ed<=r) return (node){sum[p],lm[p],rm[p]};
        int mid=(st+ed)>>1;
        if(l>mid) return findrm(rs[p],mid+1,ed,l,r);
        if(r<=mid) return findrm(ls[p],st,mid,l,r);
        return upd(findrm(ls[p],st,mid,l,r),findrm(rs[p],mid+1,ed,l,r));
    }
    inline node findlm(int p,int st,int ed,int l,int r)
    {
        if(l<=st&&ed<=r) return (node){sum[p],lm[p],rm[p]};
        int mid=(st+ed)>>1;
        if(l>mid) return findlm(rs[p],mid+1,ed,l,r);
        if(r<=mid) return findlm(ls[p],st,mid,l,r);
        return upd(findlm(ls[p],st,mid,l,r),findlm(rs[p],mid+1,ed,l,r));
    }
    inline int ask(int p,int st,int ed,int l,int r)
    {
        if(l<=st&&ed<=r) return sum[p];
        int mid=(st+ed)>>1,res=0;
        if(l<=mid) res+=ask(ls[p],st,mid,l,r);
        if(r>mid) res+=ask(rs[p],mid+1,ed,l,r);
        return res;
    }
    inline bool check(int val)
    {
        int sum1;
        if(q[2]+1<=q[3]-1) sum1=ask(rt[val],1,m,q[2]+1,q[3]-1);
        else sum1=0; 
        int sum2=findrm(rt[val],1,m,q[1],q[2]).rm;
        int sum3=findlm(rt[val],1,m,q[3],q[4]).lm;
        return (sum1+sum2+sum3)>=0;
    }
    signed main()
    {
        n=read(); 
        for(reg int i=1;i<=n;++i) a[i]=read(),b[i]=a[i]; m=n; 
        sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1;
        for(reg int i=1;i<=n;++i) 
        {
            a[i]=lower_bound(b+1,b+m+1,a[i])-b;
            g[a[i]].push_back(i);
        }
        for(reg int i=1;i<=n;++i) update(rt[1],rt[0],1,n,i,1,rt[1]?1:0);
        for(reg int i=2;i<=m;++i)
        {
            int sz=g[i-1].size(); 
            for(reg int j=0;j<sz;++j) 
                update(rt[i],rt[i-1],1,m,g[i-1][j],-1,rt[i]?1:0);
        }
        int T=read();
        while(T--)
        {
            for(reg int i=1;i<=4;++i) q[i]=(read()+lans)%n;
            sort(q+1,q+4+1); for(reg int i=1;i<=4;++i) q[i]++;
            int st=1,ed=m;
            while(st<=ed)
            {
                int mid=(st+ed)>>1;
                if(check(mid)) lans=mid,st=mid+1;
                else ed=mid-1;
            }
            printf("%lld
",lans=b[lans]);
        }
        return 0;
    }
}
signed main(){return yspm::main();}

有一说一,其实好写,花了一节多一点点自习就做完了

比那个选课简单多了

另:由于未知原因,这份代码在洛谷上过不去,然后把离散化删掉改改就能过了……

原文地址:https://www.cnblogs.com/yspm/p/13716679.html