zoukankan      html  css  js  c++  java
  • bzoj2653: middle

    题意:给n个数,每次询问a,b,c,d,你要选定一个区间使得该区间中位数最大,其中a,b为区间左端点可选范围,c,d同理。

    OTZ陈老师出的神题。

    先考虑一个简单问题:只有一个询问的情况。此时我们二分中位数,并且将区间内小中位数的数标为-1,大于的标为1,此时区间最大和如果大等0,则说明中位数可以变大,然后二分下去就可以了。

    加上询问之后,我们就要维护这样一个区间最大和了。考虑主席树,我们对于每一个值,建出它对应的1,-1树,然后二分,到对应的树上去求最大区间和就好了。那么问题来了,怎么维护这样一个最大区间和呢?首先,我们有必选区间b,c所以我要把这个区间的和算上,对于可选区间a,b-1和c+1,d,我们要求一个最大前后缀和。这个东西可以这样求(以前缀和为例):max(左儿子sum+右儿子前缀,左儿子前缀)。

    那么整体思路出来了:先建出一棵全线段树(全为1),然后我们把原序列排个序(要把下标对应好),然后一个一个按顺序丢进树里,把小等自己的变为-1,以供这个数的后一个数查询时使用。 然后我们二分答案,对于当前答案去树上找最大区间和,如果大等0则满足条件。

    这道题主席树建出来,第一维度是权值,第二维度是下标。我一开始想的一二唯独是反的,而大神说这样有问题,一直没想通哪里有问题。。。再去和大神讨论一下。

    写这道题写得异常艰难。先是在想二分会不会有问题(实际是不会的,因为题目弄出来的中位数在偶数个时会选择较大的那个)昨天晚上写了第一版,有点问题,第二天写了第二版,还是有问题,什么没有排序导致没有正确性啊,建树不分配编号啊什么的。然后各种改,终于过了(感谢ihopenot大佬)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 20005
     4 #define M 400005
     5 #define CT Chairman_Tree
     6 int n,Q,p[5],ans;
     7 struct data{
     8     int num,pos;
     9     bool operator < (const data& w)const{
    10         if(num==w.num) return pos<w.pos;
    11         return num<w.num;
    12     }
    13 }a[N]; 
    14 namespace Chairman_Tree{
    15     struct node{
    16         int son[2],sum,ls,rs;
    17     }tr[M];
    18     int sz,root[N];
    19     void build(int& x,int l,int r){
    20         x=++sz;
    21         tr[x].ls=tr[x].rs=tr[x].sum=r-l+1;
    22         if(l==r) return;
    23         int mid=(l+r)>>1;
    24         build(tr[x].son[0],l,mid);
    25         build(tr[x].son[1],mid+1,r);
    26     }
    27     void insert(int x,int& y,int l,int r,int lim){
    28         tr[y=++sz].sum=tr[x].sum-2;
    29         if(l==r){
    30             tr[y].ls=tr[y].rs=0;
    31             return;
    32         }
    33         memcpy(tr[y].son,tr[x].son,sizeof(tr[y].son));
    34         int mid=(l+r)>>1,LS,RS;
    35         if(lim>mid) insert(tr[x].son[1],tr[y].son[1],mid+1,r,lim);
    36         else insert(tr[x].son[0],tr[y].son[0],l,mid,lim);
    37         LS=tr[y].son[0],RS=tr[y].son[1];
    38         tr[y].ls=max(tr[LS].sum+tr[RS].ls,tr[LS].ls);
    39         tr[y].rs=max(tr[RS].sum+tr[LS].rs,tr[RS].rs);
    40     }
    41     inline void insert(int i) {insert(root[i],root[i+1],1,n,a[i].pos);}
    42     int query(int x,int L,int R,int l,int r){
    43         if(L==l &&     R==r) return tr[x].sum;
    44         int mid=(L+R)>>1;
    45         if(r<=mid) return query(tr[x].son[0],L,mid,l,r);
    46         else if(mid<l) return query(tr[x].son[1],mid+1,R,l,r);
    47         else return query(tr[x].son[0],L,mid,l,mid)+query(tr[x].son[1],mid+1,R,mid+1,r);
    48     }
    49     int lquery(int x,int L,int R,int l,int r){
    50         if(L==l && R==r) return tr[x].ls;
    51         int mid=(L+R)>>1;
    52         if(r<=mid) return lquery(tr[x].son[0],L,mid,l,r);
    53         else if(mid<l) return lquery(tr[x].son[1],mid+1,R,l,r);
    54         else {
    55         int t1=query(tr[x].son[0],L,mid,l,mid)+lquery(tr[x].son[1],mid+1,R,mid+1,r),t2=lquery(tr[x].son[0],L,mid,l,mid);
    56         return max(t1,t2);
    57         }
    58     }
    59     int rquery(int x,int L,int R,int l,int r){
    60         if(L==l && R==r) return tr[x].rs;
    61         int mid=(L+R)>>1;
    62         if(r<=mid) return rquery(tr[x].son[0],L,mid,l,r);
    63         else if(mid<l) return rquery(tr[x].son[1],mid+1,R,l,r);
    64         else {
    65         int t1=rquery(tr[x].son[0],L,mid,l,mid)+query(tr[x].son[1],mid+1,R,mid+1,r),t2=rquery(tr[x].son[1],mid+1,R,mid+1,r); 
    66         return max(t1,t2);
    67         }
    68     }
    69 }
    70 using namespace CT;
    71 inline int read(){
    72     int x=0,f=1; char a=getchar();
    73     while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
    74     while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
    75     return x*f;
    76 }
    77 inline bool jud(int x){
    78     return rquery(root[x],1,n,p[1],p[2]-1)+query(root[x],1,n,p[2],p[3])+lquery(root[x],1,n,p[3]+1,p[4])>=0;
    79 }
    80 int main(){
    81     n=read();
    82     for(int i=1;i<=n;i++) a[i]=(data){read(),i};
    83     build(root[1],1,n);
    84     sort(a+1,a+1+n);
    85     for(int i=1;i<n;i++) insert(i);
    86     Q=read();
    87     while(Q--){
    88         int l=1,r=n;
    89         for(int i=1;i<=4;i++) p[i]=(read()+ans)%n+1;
    90         sort(p+1,p+5);
    91         while(l<r){
    92             int mid=(l+r+1)>>1;
    93             if(jud(mid)) l=mid;
    94             else r=mid-1;
    95         }
    96         ans=a[l].num; printf("%d
    ",ans);
    97     }
    98     return 0;
    99 }
  • 相关阅读:
    不用google 是不行的
    一些主题
    腾讯cdc空间
    断言assert的使用
    malloc()和free()的相关知识
    linux上面的sz,rz命令与ssh的配合
    寻找第k小的元素
    c语言中字符串处理函数
    详解之#ifdef和#ifndef
    搭建测试环境linux静态链接库与动态链接库的区别及动态库的创建
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6202920.html
Copyright © 2011-2022 走看看