zoukankan      html  css  js  c++  java
  • [BZOJ2653]middle(二分+主席树)

    2653: middle

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 2252  Solved: 1252
    [Submit][Status][Discuss]

    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

    Sample Output

     

    HINT

      0:n,Q<=100

    1,...,5:n<=2000

    0,...,19:n<=20000,Q<=25000


    Source

     
    [Submit][Status][Discuss]

    关于中位数的题一般首先二分答案,然后根据大于此数和小于此数的个数判断,这题中如果大于等于此数的数-小于此数的数得到的结果大于0则说明中位数可能更大。

    换句话说就是所有大于等于的位置赋为1,小于赋为-1,则一段区间和非负。

    但是每次二分都要全部赋值一次吗?不需要,因为考虑每相邻的两个权值从1变到-1的数是不多的,用主席树先全部建好就可以了。

    需要同时维护三个值:lmax,rmax,sum,发现合并lmax和rmax的时候需要sum,那么这个复杂度还能保证吗?答案是肯定的,因为最多每个点的常数*2,复杂度是不会变的。当然也可以每次将三个点放在一起合并,复杂度不变。

    最后,这题第一行的排序是指从小到大排序的。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define lson ls[x],L,mid
     4 #define rson rs[x],mid+1,R
     5 #define rep(i,l,r) for (int i=l; i<=r; i++)
     6 using namespace std;
     7 
     8 const int N=5000100;
     9 struct P{
    10     int sm,lmx,rmx; P(){};
    11     P(int _sm,int _lmx,int _rmx):sm(_sm),lmx(_lmx),rmx(_rmx){}
    12 }seg[N];
    13 int ls[N],rs[N],T[30010],q[4],ans,nd,n,Q;
    14 struct A{
    15     int x,y;
    16     bool operator <(const A &a)const{ return (x==a.x) ? y<a.y : x<a.x; }
    17 }a[30010];
    18 
    19 P operator +(const P &a,const P &b){ return P(a.sm+b.sm,max(a.lmx,a.sm+b.lmx),max(b.rmx,b.sm+a.rmx)); }
    20 
    21 void build(int &x,int L,int R){
    22     x=++nd;
    23     if (L==R){ seg[x]=P(1,1,1); return; }
    24     int mid=(L+R)>>1; build(lson); build(rson);
    25     seg[x]=seg[ls[x]]+seg[rs[x]];
    26 }
    27 
    28 void mdf(int y,int &x,int L,int R,int pos){
    29     x=++nd; ls[x]=ls[y]; rs[x]=rs[y];
    30     if (L==R){ seg[x]=P(-1,-1,-1); return; }
    31     int mid=(L+R)>>1;
    32     if (pos<=mid) mdf(ls[y],lson,pos); else mdf(rs[y],rson,pos);
    33     seg[x]=seg[ls[x]]+seg[rs[x]];
    34 }
    35 
    36 P ask(int x,int L,int R,int l,int r){
    37     if (l>r) return P(0,0,0);
    38     if (L==l && r==R) return seg[x];
    39     int mid=(L+R)>>1;
    40     if (r<=mid) return ask(lson,l,r);
    41     else if (l>mid) return ask(rson,l,r);
    42         else return ask(lson,l,mid)+ask(rson,mid+1,r);
    43 }
    44 
    45 int jud(int k){ return ask(T[k],1,n,q[0],q[1]).rmx+ask(T[k],1,n,q[1]+1,q[2]-1).sm+ask(T[k],1,n,q[2],q[3]).lmx>=0; }
    46 
    47 int main(){
    48     freopen("bzoj2653.in","r",stdin);
    49     freopen("bzoj2653.out","w",stdout);
    50     scanf("%d",&n);
    51     rep(i,1,n) scanf("%d",&a[a[i].y=i].x);
    52     sort(a+1,a+n+1); build(T[1],1,n);
    53     rep(i,2,n) mdf(T[i-1],T[i],1,n,a[i-1].y);
    54     scanf("%d",&Q);
    55     while (Q--){
    56         scanf("%d%d%d%d",&q[0],&q[1],&q[2],&q[3]);
    57         q[0]=(q[0]+ans)%n+1; q[1]=(q[1]+ans)%n+1;
    58         q[2]=(q[2]+ans)%n+1; q[3]=(q[3]+ans)%n+1; sort(q,q+4);
    59         int L=1,R=n;
    60         while (L<=R){
    61             int mid=(L+R)>>1;
    62             if (jud(mid)) L=mid+1; else R=mid-1;
    63         }
    64         printf("%d
    ",ans=a[L-1].x);
    65     }
    66     return 0;
    67 }
  • 相关阅读:
    引用类型之Object类
    原始类型之String类型
    原始类型之Boolean类型
    引用类型之Boolean类
    引用类型之instanceof运算符
    javascript类型转换
    运算符之一元运算符
    Google Sites开始向所有人免费开放 可自由建个人主页
    在线制作"篆体印章",很酷!
    MD5 哈希计算工具类
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8987648.html
Copyright © 2011-2022 走看看