zoukankan      html  css  js  c++  java
  • [国家集训队]middle

    题目描述

    一个长度为 $n$ 的序列 $a$,设其排过序之后为$b$,其中位数定义为 $b_{n/2}$,其中 $a,b$ 从 $0$ 开始标号,除法取下整。

    给你一个长度为$n$ 的序列 $s$

    回答 $Q$ 个这样的询问:$s$ 的左端点在 $[a,b]$ 之间,右端点在 $[c,d]$ 之间的子区间中,最大的中位数。

    其中 $a<b<c<d$

    位置也从 $0$ 开始标号。

    我会使用一些方式强制你在线。

    输入格式

    第一行序列长度 $n$

    接下来 $n$ 行按顺序给出$a$ 中的数。

    接下来一行 $Q$

    然后 $Q$ 行每行 $a,b,c,d$,我们令上个询问的答案是 $x$(如果这是第一个询问则 $x=0$)。

    令数组 $q={(a+x)mod n,(b+x)mod n,(c+x)mod n,(d+x)mod n}$

    将 $q$ 从小到大排序之后,令真正的要询问的 $a=q_0,b=q_1,c=q_2,d=q_3$

    输入保证满足条件。

    输出格式

    $Q$ 行依次给出询问的答案。

    输入输出样例

    输入 
    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0
    输出
    271451044
    271451044
    969056313

    说明/提示

    对于$5\%$的数据, $n,Q leq 100$

    对于另 $25\%$ 的数据,$n leq 2000$

    对于 $100\%$ 的数据, $n leq 20000$$Q leq 25000$


    $Solution:$

      主席树好题。

      因为是要我们求中位数,所以惯用的套路就是二分一个$mid$,然后大于等于$mid$的看成$1$,小于$mid$的看成$-1$,然后我们求一下区间和, 

    如果区间和大于等于$0$的话就说明中位数只能更大,令$l=mid+1$,如果区间和小于$0$的话就令$r=mid-1$,继续二分。

      因为我们要中位数尽可能地大,所以我们要求的区间和尽可能大,但是这道题的区间不确定。经过思考我们发现$[b+1,c-1]$这个区间是必选的,

    也就是说这个区间是确定的,所以我们只要让$[a,b]$的右端最大子段和$+$ $[c,d]$的左端最大子段和最大即可。

      这个显然是可以用线段树维护的。

      所以我们得出了一个做法:先把$a[]$排序一下。对于每一个二分出来的$mid$,首先给区间$[a,d]$赋值,然后以区间为下标建立一棵线段树并同时

    维护一下每一个区间的区间和,左端最大子段和,右端最大子段和。然后再在$[a,b]$求出它的最大后缀,$[c,d]$中求出它的最大前缀,再加一下$[b+1,c-1]$

    这个区间的区间和然后判一下是否大于等于$0$,继续二分。。。

      但是这样空间显然会炸,所以我们还要继续优化。

      我们可以发现对于$mid$来说,如果我们的$mid+1$的话,受到影响的值只有$mid$——从$+1$变成$-1$,所以我们可以用主席树暴力修改该位置上的值就$OK$了。


     

    $Code:$

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int N=20010;
      4 int n,lmax[N*20],rmax[N*20],lc[N*20],rc[N*20],sum[N*20],rt[N*20],cnt;
      5 void push_down(int p){
      6     sum[p]=sum[lc[p]]+sum[rc[p]];
      7     lmax[p]=max(lmax[lc[p]],sum[lc[p]]+lmax[rc[p]]);
      8     rmax[p]=max(rmax[rc[p]],sum[rc[p]]+rmax[lc[p]]);
      9 }
     10 void copy(int now,int pre){
     11     lc[now]=lc[pre];
     12     rc[now]=rc[pre];
     13     lmax[now]=lmax[pre];
     14     rmax[now]=rmax[pre];
     15     sum[now]=sum[pre];
     16 }
     17 int build(int l,int r){
     18     int p=++cnt;
     19     if(l==r){
     20         lmax[p]=rmax[p]=sum[p]=1;
     21         return p;
     22     }
     23     int mid=(l+r)>>1;
     24     lc[p]=build(l,mid);
     25     rc[p]=build(mid+1,r);
     26     push_down(p);
     27     return p;
     28 }
     29 void ins(int &p,int pre,int l,int r,int x,int val){
     30     p=++cnt;
     31     copy(p,pre);
     32     if(l==r){
     33         lmax[p]=rmax[p]=sum[p]=val;
     34         return;
     35     }
     36     int mid=(l+r)>>1;
     37     if(x<=mid) ins(lc[p],lc[pre],l,mid,x,val);
     38     else ins(rc[p],rc[pre],mid+1,r,x,val);
     39     push_down(p);
     40 }
     41 int query_sum(int p,int l,int r,int L,int R){
     42     int res=0;
     43     if(L<=l&&r<=R)
     44         return sum[p];
     45     int mid=(l+r)>>1;
     46     if(L<=mid) res+=query_sum(lc[p],l,mid,L,R);
     47     if(R>mid) res+=query_sum(rc[p],mid+1,r,L,R);
     48      return res;
     49 }
     50 int query_lsum(int p,int l,int r,int a,int b){
     51     if(a<=l&&r<=b)
     52         return lmax[p];
     53     int mid=(l+r)>>1;
     54     if(b<=mid) return query_lsum(lc[p],l,mid,a,b);
     55     else if(a>=mid+1) return query_lsum(rc[p],mid+1,r,a,b);
     56     else return max(query_sum(lc[p],l,mid,a,mid)+query_lsum(rc[p],mid+1,r,mid+1,b),query_lsum(lc[p],l,mid,a,mid));
     57 }
     58 int query_rsum(int p,int l,int r,int c,int d){
     59     if(c<=l&&r<=d)
     60         return rmax[p];
     61     int mid=(l+r)>>1;
     62     if(d<=mid) return query_rsum(lc[p],l,mid,c,d);
     63     else if(c>=mid+1) return query_rsum(rc[p],mid+1,r,c,d);
     64     else return max(query_rsum(rc[p],mid+1,r,mid+1,d),query_rsum(lc[p],l,mid,c,mid)+query_sum(rc[p],mid+1,r,mid+1,d));
     65 }
     66 bool check(int mid,int a,int b,int c,int d){
     67     int sum=0;
     68     if(b+1<=c-1)
     69         sum+=query_sum(rt[mid],1,n,b+1,c-1);
     70     sum+=query_rsum(rt[mid],1,n,a,b);
     71     sum+=query_lsum(rt[mid],1,n,c,d);
     72     return sum>=0;
     73 }
     74 struct data{
     75     int x,pos;
     76 }a[N];
     77 bool cmp(data a,data b){
     78     return a.x<b.x;
     79 }
     80 int main(){
     81     scanf("%d",&n);
     82     for(int i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].pos=i;
     83     sort(a+1,a+1+n,cmp);
     84     rt[1]=build(1,n);
     85     for(int i=2;i<=n+1;i++)
     86         ins(rt[i],rt[i-1],1,n,a[i-1].pos,-1);
     87     int Q,lastans=0;
     88     scanf("%d",&Q);
     89     while(Q--){
     90         int q[10],id;
     91         scanf("%d%d%d%d",&q[1],&q[2],&q[3],&q[4]);
     92         for(int i=1;i<=4;i++) q[i]=(q[i]+lastans)%n;
     93         sort(q+1,q+1+4);
     94         int l=1,r=n;
     95         while(l<=r){
     96             int mid=(l+r)>>1;
     97             if(check(mid,q[1]+1,q[2]+1,q[3]+1,q[4]+1)) l=mid+1,id=mid;
     98             else r=mid-1;
     99         }
    100         lastans=a[id].x;
    101         printf("%d
    ",lastans);
    102     }
    103     return 0;
    104 }
     
  • 相关阅读:
    VS2010 枚举注释任务
    osg例子中文翻译,半机翻
    怎么愉快地添加目标位置?
    变更路线节点。妈妈,我的强迫症有救啦!
    测试必备工具之抓包神器 Charles 如何抓取 https 数据包?
    测试必备工具之最强抓包神器 Charles,你会了么?
    ‘员工拒绝加班被判赔偿公司 1.8 万元’,作为测试猿你怕了么?
    全网最全测试点总结:N95 口罩应该如何测试?
    测试角度:如何看待三星大量手机系统崩溃并数据丢失事件?
    男生 vs 女生,谁更加适合做软件测试?
  • 原文地址:https://www.cnblogs.com/sbwll/p/14346950.html
Copyright © 2011-2022 走看看