zoukankan      html  css  js  c++  java
  • bzoj2653 middle

    题意:给你一个数列,每次询问左端点在[a,b]中,右端点在[c,d]中的所有子区间的中位数最大值?

    n<=1e5.

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5    int x=0,f=1;char ch=getchar();
     6    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
     7    while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
     8    return x*f;
     9 }
    10 const int N=800005;
    11 const int inf=0x3f3f3f3f;
    12 int sc,rm[N],lm[N],ls[N],rs[N],rt[N],q[5],n,a[N],b[N],Q,x,l,r,sum[N];
    13 void up(int k)
    14 {
    15     sum[k]=sum[ls[k]]+sum[rs[k]];
    16     lm[k]=max(lm[ls[k]],sum[ls[k]]+lm[rs[k]]);
    17     rm[k]=max(rm[rs[k]],sum[rs[k]]+rm[ls[k]]);
    18 }
    19 void build(int &k,int l,int r)
    20 {
    21     k=++sc;
    22    if (l==r) {lm[k]=rm[k]=sum[k]=1;return;}
    23    int mid=(l+r)>>1;
    24    build(ls[k],l,mid);build(rs[k],mid+1,r);
    25    up(k);
    26 }
    27 void ins(int &k,int pk,int l,int r,int x)
    28 {
    29    k=++sc;ls[k]=ls[pk];rs[k]=rs[pk];
    30     if (l==r) {lm[k]=rm[k]=sum[k]=-1;return;}
    31     int mid=(l+r)>>1;
    32     if (x<=mid) ins(ls[k],ls[pk],l,mid,x);
    33     else ins(rs[k],rs[pk],mid+1,r,x);
    34     up(k);
    35 }
    36 int qry_sum(int k,int l,int r,int L,int R)
    37 {
    38     if (L>R) return 0;
    39     if (L<=l&&r<=R) return sum[k];
    40     int mid=(l+r)>>1,res=0;
    41     if (L<=mid) res+=qry_sum(ls[k],l,mid,L,R);
    42     if (R>mid) res+=qry_sum(rs[k],mid+1,r,L,R);
    43     return res;
    44 }
    45 int qry_lm(int k,int l,int r,int L,int R)
    46 {
    47     if (L==l&&r==R) return lm[k];
    48     int mid=(l+r)>>1;
    49     if (L>mid) return qry_lm(rs[k],mid+1,r,L,R);
    50     else if (R<=mid) return qry_lm(ls[k],l,mid,L,R);
    51     else return max(qry_lm(ls[k],l,mid,L,mid),qry_sum(ls[k],l,mid,L,mid)+qry_lm(rs[k],mid+1,r,mid+1,R));
    52 }
    53 int qry_rm(int k,int l,int r,int L,int R)
    54 {
    55     if (L==l&&r==R) return rm[k];
    56     int mid=(l+r)>>1;
    57     if (L>mid) return qry_rm(rs[k],mid+1,r,L,R);
    58     else if (R<=mid) return qry_rm(ls[k],l,mid,L,R);
    59     else return max(qry_rm(rs[k],mid+1,r,mid+1,R),qry_sum(rs[k],mid+1,r,mid+1,R)+qry_rm(ls[k],l,mid,L,mid));
    60 }
    61 bool cmp(int x,int y){return a[x]<a[y];}
    62 bool check(int x)
    63 {
    64     return qry_rm(rt[x],1,n,q[1],q[2])+qry_sum(rt[x],1,n,q[2]+1,q[3]-1)+qry_lm(rt[x],1,n,q[3],q[4])>=0;
    65 }
    66 int main()
    67 {
    68     n=read();
    69     for (int i=1;i<=n;i++) a[i]=read(),b[i]=i;
    70     sort(b+1,b+n+1,cmp);
    71    build(rt[1],1,n);
    72     for (int i=2;i<=n;i++) ins(rt[i],rt[i-1],1,n,b[i-1]);
    73     Q=read();
    74     while (Q--)
    75     {
    76         for (int i=1;i<=4;i++) q[i]=(read()+x)%n+1;
    77         sort(q+1,q+5);
    78         l=1;r=n;
    79         while (l<=r)
    80         {
    81             int mid=(l+r)>>1;
    82             if (check(mid)) x=mid,l=mid+1;else r=mid-1; 
    83         }
    84         printf("%d
    ",x=a[b[x]]);
    85     }
    86    return 0;
    87 }

    易错点:1.强在,忘了把x更新掉。

    2.一开始写的是线段树直接维护前缀和。但是这个区间加等差数列比较麻烦,当然也不是不行。

    题解:主席树+二分答案

    中位数、平均数什么的经典套路就是二分答案。把区间中>=x的设置成1,<x的设置成-1,所以如果有合法区间满足最大区间和>=0,则x可行。

    按值依次建立主席树,每次只会增加一条修改为-1的链。(这里不用离散化)

    维护前缀最大和后缀最大,还有和。

    查询的时候就是前面一段的最大后缀+中间一段的和+后面一段的最大前缀。

  • 相关阅读:
    spring04
    kepp running 团队视频分析初步总结
    spring03
    第六周学习进度博客
    spring02
    spring初级java 应用。搭建环境。基本语法
    给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表
    团队项目-运动App
    第五周学习进度博客
    java编写规范
  • 原文地址:https://www.cnblogs.com/Scx117/p/9078294.html
Copyright © 2011-2022 走看看