• 【BZOJ2653】Middle(主席树)


    【BZOJ2653】Middle(主席树)

    题面

    BZOJ
    洛谷

    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

    271451044

    271451044

    969056313

    题解

    陈老师神题啊,丽洁姐最神啦

    还是二分答案
    区间内的中位数大于一个值?
    将大于答案的数赋值为(1),小于的赋值(-1)
    既然是左端点在([a,b]),右端点在([c,d])
    那么也就是([b+1,c-1])必须选
    而现在要中位数尽可能大
    所以要选的就是([a,b])的最大右子段和
    ([c,d])的最大左子段和

    而答案一定是某个数列中的数
    排序之后依次把自己位置上的(1)变成(-1)即可
    不可能开这么多线段树
    显然是在主席树上直接修改

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 22222
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Node
    {
        int lv,rv,sum;
        int ls,rs,id;
    }t[MAX<<6];
    Node operator+(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;
        c.ls=a.id;c.rs=b.id;
        return c;
    }
    int tot,rt[MAX];
    void Build(int &x,int l,int r)
    {
        x=++tot;t[x].id=x;
        if(l==r){t[x].lv=t[x].rv=t[x].sum=1;return;}
        int mid=(l+r)>>1;
        Build(t[x].ls,l,mid);Build(t[x].rs,mid+1,r);
        t[x]=t[t[x].ls]+t[t[x].rs];t[x].id=x;
    }
    void Modify(int &x,int ff,int l,int r,int p,int w)
    {
        t[x=++tot]=t[ff];t[x].id=x;
        if(l==r){t[x].lv=t[x].rv=t[x].sum=t[x].sum+w;return;}
        int mid=(l+r)>>1;
        if(p<=mid)Modify(t[x].ls,t[ff].ls,l,mid,p,w);
        else Modify(t[x].rs,t[ff].rs,mid+1,r,p,w);
        t[x]=t[t[x].ls]+t[t[x].rs];t[x].id=x;
    }
    Node Query(int x,int l,int r,int L,int R)
    {
        if(l==L&&r==R)return t[x];
        int mid=(l+r)>>1;
        if(R<=mid)return Query(t[x].ls,l,mid,L,R);
        if(L>mid)return Query(t[x].rs,mid+1,r,L,R);
        return Query(t[x].ls,l,mid,L,mid)+Query(t[x].rs,mid+1,r,mid+1,R);
    }
    int n,a[MAX],p[MAX];
    bool cmp(int x,int y){return a[x]<a[y];}
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i)a[i]=read();
        for(int i=1;i<=n;++i)p[i]=i;
        Build(rt[1],1,n);
        sort(&p[1],&p[n+1],cmp);
        for(int i=1;i<=n;++i)
        	Modify(rt[i+1],rt[i],1,n,p[i],-2);
        sort(&a[1],&a[n+1]);
        int Q=read();
        int ans=0,q[5];
        while(Q--)
        {
            for(int i=1;i<=4;++i)q[i]=(read()+ans)%n+1;
            sort(&q[1],&q[5]);
            int l=1,r=n,Ans=1;
            while(l<=r)
            {
                int mid=(l+r)>>1,ss=0;
                if(q[2]+1<=q[3]-1)ss+=Query(rt[mid],1,n,q[2]+1,q[3]-1).sum;
                ss+=Query(rt[mid],1,n,q[1],q[2]).rv;
                ss+=Query(rt[mid],1,n,q[3],q[4]).lv;
                if(ss>=0)Ans=mid,l=mid+1;
                else r=mid-1;
            }
            printf("%d
    ",ans=a[Ans]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    java.lang.NoClassDefFoundError: org/apache/commons/fileupload/disk/DiskFileItemFactory
    连续子数组的最大和
    @Scheduled(cron = "* * * * * *")
    BigDecimal加减乘除计算
    04
    作业03
    作业01
    Haar小波的理解
    Matlab画colormap的一种色彩搭配方法
    单自由度系统中质量、阻尼和刚度变化对频率响应函数(FRF)影响图的绘制
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8705616.html
Copyright © 2020-2023  润新知