• [国家集训队]middle 题解


    题面传送门

    这道题我们首先会想到处理中位数的常见方法:

    二分枚举答案ans,将大于ans的数变为1,小于的则变成-1;如果这个区间的和大于1,则说明中位数比枚举的答案要大,否则要小;

    但是这道题的区间并不确定,难道我们要n*n枚举?肯定不行;

    观察性质,我们发现,对于区间[b,c],我们肯定要选择,那么先把这个区间的和加入到答案里;

    因为题中说选择尽量大的中位数,根据二分时的性质,区间和越大,中位数越大;所以我们所选择的区间的和要最大;

    也就是说,我们还要选取rmax[a,b]和lmax[c,d];

    综上所述,对于每次二分的判定,如果rmax[a,b]+lmax[c,d]+sum(b,c)>=0,则说明中位数比现在枚举的答案大,然后更改二分条件L=mid+1;

    我们可以对于每次二分的答案将区间改成01序列,利用线段树可以做到nlogn;

    可是这样空间复杂度原地爆炸,于是想到了我们的好朋友:主席树;

    发现:如果二分的答案ans变为ans+1,那么ans+1所对应的线段树上相对于ans的线段树只有等于ans+1的点的权值有所变动,显然每次多需要建的树节点均摊下来只有(logn);

    于是开心的用$nlog ^{2}n$的时间复杂度AC掉了这道题;

    #include <bits/stdc++.h>
    #define inc(i,a,b) for(register int i=a;i<=b;i++)
    using namespace std;
    int aa[20010],lisan;
    int in[10],root[20010];
    class node2{
        public:
        int x,id;
    }query[200010];
    bool cmp(node2 x,node2 y){
        return x.x<y.x;
    }
    class node{
        public:
        int lson,rson;
        int sum,lmax,rmax;
        #define mid (l+r)/2
    }tree[2000010];
    int tot;
    void updata(int k){
        tree[k].sum=tree[tree[k].lson].sum+tree[tree[k].rson].sum;
        tree[k].lmax=max(tree[tree[k].lson].lmax,tree[tree[k].rson].lmax+tree[tree[k].lson].sum);
        tree[k].rmax=max(tree[tree[k].rson].rmax,tree[tree[k].lson].rmax+tree[tree[k].rson].sum);
    }
    int build(int l,int r){
        int root=++tot;
        if(l==r){
            tree[root].sum=tree[root].lmax=tree[root].rmax=1;
            return root;
        }
        tree[root].lson=build(l,mid);
        tree[root].rson=build(mid+1,r);
        updata(root); return root;
    }
    void add(int &now,int pre,int l,int r,int goal,int value){
        now=++tot;
        tree[now]=tree[pre];
        if(l==r){
            tree[now].lmax=tree[now].rmax=tree[now].sum=value;
            return;
        }
        if(goal<=mid){
            add(tree[now].lson,tree[pre].lson,l,mid,goal,value);
        }
        else{
            add(tree[now].rson,tree[pre].rson,mid+1,r,goal,value);
        }
        updata(now);
    }
    int querysum(int now,int l,int r,int x,int y){
        if(x>r||y<l) return 0;
        if(x<=l&&r<=y) return tree[now].sum;
        return (querysum(tree[now].lson,l,mid,x,y)+querysum(tree[now].rson,mid+1,r,x,y));
    }
    int querylmax(int now,int l,int r,int x,int y){
        if(x>r||y<l) return -99999999;
        if(x<=l&&r<=y) return tree[now].lmax;
        return max(querylmax(tree[now].lson,l,mid,x,y),querylmax(tree[now].rson,mid+1,r,x,y)+querysum(tree[now].lson,l,mid,x,y));
    }
    int queryrmax(int now,int l,int r,int x,int y){
        if(x>r||y<l) return -99999999;
        if(x<=l&&r<=y) return tree[now].rmax;
        int tmp1=queryrmax(tree[now].rson,mid+1,r,x,y),tmp2=queryrmax(tree[now].lson,l,mid,x,y)+querysum(tree[now].rson,mid+1,r,x,y);
        return max(tmp1,tmp2);
    }
    int n; 
    bool check(int now,int a,int b,int c,int d){
        int sum=0;
        if(b+1<=c-1) sum+=querysum(root[now],1,n,b+1,c-1);
        sum+=queryrmax(root[now],1,n,a,b);
        sum+=querylmax(root[now],1,n,c,d);
        if(sum>=0) return 1;
        else return 0;
    }
    int main()
    {
        scanf("%d",&n);
        inc(i,1,n){
            scanf("%d",&query[i].x);
            query[i].id=i;
        }
        sort(query+1,query+1+n,cmp);
        root[1]=build(1,n);
        inc(i,2,n+1){
            add(root[i],root[i-1],1,n,query[i-1].id,-1);
        }
        int q; scanf("%d",&q);
        int ans=0;
        inc(i,1,q){
            scanf("%d%d%d%d",&in[0],&in[1],&in[2],&in[3]);
            in[0]=(in[0]+ans)%n; in[1]=(in[1]+ans)%n; in[2]=(in[2]+ans)%n; in[3]=(in[3]+ans)%n;
            sort(in,in+4);
            int L=1,R=n;
            while(L<=R){
                int midd=(L+R)/2;
                if(check(midd,in[0]+1,in[1]+1,in[2]+1,in[3]+1)){
                    L=midd+1; ans=midd;
                }
                else{
                    R=midd-1;
                }
            }
            ans=query[ans].x;
            printf("%d
    ",ans);
        }
    }
    /*
    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0
    */
  • 相关阅读:
    [图解数据结构] 线性表
    利用爬虫获取网上医院药品价格信息 (上)
    手把手教你写网络爬虫(1):网易云音乐歌单
    用python实现与小米网关通讯
    eclipse添加lombok无法启动
    mongodb数据出现undefined如何查询
    初探active mq
    base64和图片互转
    设置Linux下Mysql表名不区分大小写
    Windows下安装MySQL5.6绿色版
  • 原文地址:https://www.cnblogs.com/kamimxr/p/12108639.html
Copyright © 2020-2023  润新知