• Luogu P2839 [国家集训队]middle


    题目
    首先我们考虑解决中位数一类问题的常用手段:二分(mid),将大于等于它的设为(1),小于它的设为(−1),判断区间和是否(ge0)
    对于询问(a,b,c,d),二分完(mid)后,我们需要判断([a,b])的最大后缀和(+[c,d])的最大前缀和(+(b,c))的和是否(ge0)
    因为中位数一定是序列中出现过的数,所以我们可以排序后二分第(mid)大。
    考虑使用主席树维护区间和区间最大后缀和区间最大前缀和。
    最开始先把所有数设为(1)建树。
    然后每次从小到大把序列中的一个树改为(-1)建一个新版本。
    查询的时候按上面的来就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[20],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
        void Put(char x){*oS++=x;if(oS==oT)Flush();}
        int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
        void write(int x){int top=0;while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
    ');}
    }
    using namespace IO;
    int max(int a,int b){return a>b? a:b;}
    #define N 100007
    #define mid ((l+r)>>1)
    int root[N],q[4],id[N],a[N],ls[N<<4],rs[N<<4],cnt,n;
    struct node{int lv,rv,sum;void init(){lv=rv=-N,sum=0;}}Ans,v[N<<4];
    int cmp(int x,int y){return a[x]<a[y];}
    node merge(node a,node b)
    {
        node c;
        c.lv=max(a.lv,a.sum+b.lv);
        c.rv=max(b.rv,b.sum+a.rv);
        c.sum=a.sum+b.sum;
        return c;
    }
    void build(int &p,int l,int r)
    {
        p=++cnt,v[p].lv=v[p].rv=v[p].sum=r-l+1;
        if(l^r) build(ls[p],l,mid),build(rs[p],mid+1,r);
    }
    void modify(int &p,int l,int r,int x)
    {
        v[++cnt]=v[p],ls[cnt]=ls[p],rs[cnt]=rs[p],p=cnt;
        if(l==r) return (void)(v[p].lv=v[p].rv=v[p].sum=-1);
        (x<=mid? modify(ls[p],l,mid,x):modify(rs[p],mid+1,r,x)),v[p]=merge(v[ls[p]],v[rs[p]]);
    }
    void query(int p,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R) return (void)(Ans=merge(Ans,v[p]));
        if(L<=mid) query(ls[p],l,mid,L,R);
        if(R>mid) query(rs[p],mid+1,r,L,R);
    }
    int check(int p)
    {
        int sum=0;
        if(q[1]+1<=q[2]-1) Ans.init(),query(root[p],1,n,q[1]+1,q[2]-1),sum+=Ans.sum;
        Ans.init(),query(root[p],1,n,q[0],q[1]),sum+=Ans.rv;
        Ans.init(),query(root[p],1,n,q[2],q[3]),sum+=Ans.lv;
        return sum>=0;
    }
    int main()
    {
        int i,Q,ans,l,r;
        n=read(),build(root[1],1,n),v[0].init();
        for(i=1;i<=n;++i) a[i]=read(),id[i]=i;
        sort(id+1,id+n+1,cmp);
        for(i=2;i<=n;++i) root[i]=root[i-1],modify(root[i],1,n,id[i-1]);
        for(Q=read(),ans=0;Q;--Q)
        {
    	for(i=0;i<4;++i) q[i]=(read()+ans)%n+1;
    	sort(q,q+4),l=1,r=n;
    	while(l<=r) check(mid)? (ans=a[id[mid]],l=mid+1):(r=mid-1);
    	write(ans);
        }
        return Flush(),0;
    }
    
  • 相关阅读:
    看到你还在用Maven,Gradle难道不香吗?
    技术干货|完美搭建web自动化环境
    使用可视化的Docker进行自动化测试
    使用Robot Framework实现多平台自动化测试
    还在手工写接口测试文档吗,已经out了
    巧用Python脚本解决自动化图形验证码难题
    为什么要进行URL编码
    C# (CLR) 中内存分配解析
    DIV+CSS规范命名大全集合
    Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11543848.html
Copyright © 2020-2023  润新知