bzoj2653: middle

Posted Izaya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",ans);
97     }
98     return 0;
99 }

 

以上是关于bzoj2653: middle的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2653 middle

[BZOJ2653]middle

bzoj2653 middle

[BZOJ2653]middle 主席树+二分

bzoj 2653middle

[BZOJ 2653]middle