bzoj2653: middle

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

 

题解:

这道题是基于这么个idea,如何在不求出一个数列a的中位数的情况下,判断数x是大于等于中位数

我们可以考虑定义一个新数列b,满足b[i]= a[i]>=x?1:-1 ,如果b数列的总和大于等于0,则数x小于等于中位数,否则反之

然后这道题我们可以二分一个数x,判断是否能成为中位数,我们可以将大于等于x的数看成1,小于的看成-1

查询左端点在 [ a , b ] , 右端点在 [ c , d ] 的最大子段和,如果最大子段和大于等于0,说明x小于等于中位数,否则反之

但现在x是变化的,我们显然不能每次暴力把某个数改成1或-1

显然x只能是原序列的数

将原序列的数离散化一下后,此时x的取值范围显然是1到n,我们发现当x变成x+1时,只有第x个数由+1变为-1

而对于某个序列的最大子段和显然可以用线段树维护,而每次只会修改一个数

我们就可以用可持久化线段树把历史上每个线段树都建出来,然后在第x个上进行查询

总的时间复杂度为O( n log 2 n )

code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 char ch;
 8 bool ok;
 9 void read(int &x){
10     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
11     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
12     if (ok) x=-x;
13 }
14 const int maxn=20005;
15 const int maxnode=310000;
16 const int inf=0x7f7f7f7f;
17 int n,q,t[4],ans;
18 struct Data{
19     int v,id;
20     void init(int i){read(v),id=i;}
21 }list[maxn];
22 bool cmp(const Data &a,const Data &b){return a.v<b.v;}
23 struct Node{
24     int lmax,rmax,maxv,sum;
25     void init(int v){lmax=rmax=maxv=sum=v;}
26 }t1,t2,t3;
27 Node operator+(const Node &x,const Node &y){
28     return (Node){max(x.lmax,x.sum+y.lmax),max(y.rmax,y.sum+x.rmax),max(x.rmax+y.lmax,max(x.maxv,y.maxv)),x.sum+y.sum};
29 }
30 struct seg{
31     int tot,root[maxn],son[maxnode][2];
32     Node node[maxnode];
33     void build(int &k,int l,int r){
34         k=++tot;
35         if (l==r){node[k].init(1);return;}
36         int m=(l+r)>>1;
37         build(son[k][0],l,m),build(son[k][1],m+1,r),node[k]=node[son[k][0]]+node[son[k][1]];
38     }
39     void modify(int &k,int p,int l,int r,int x){
40         k=++tot;
41         if (l==r){node[k].init(-1);return;}
42         int m=(l+r)>>1;
43         if (x<=m) son[k][1]=son[p][1],modify(son[k][0],son[p][0],l,m,x);
44         else son[k][0]=son[p][0],modify(son[k][1],son[p][1],m+1,r,x);
45         node[k]=node[son[k][0]]+node[son[k][1]];
46     }
47     void modify(int id,int x){modify(root[id],root[id-1],1,n,x);}
48     Node query(int k,int l,int r,int x,int y){
49         if (l==x&&r==y) return node[k];
50         int m=(l+r)>>1;
51         if (y<=m) return query(son[k][0],l,m,x,y);
52         else if (x<=m) return query(son[k][0],l,m,x,m)+query(son[k][1],m+1,r,m+1,y);
53         else return query(son[k][1],m+1,r,x,y);
54     }
55     Node query(int id,int x,int y){return x<=y?query(root[id],1,n,x,y):(Node){-inf,-inf,-inf,0};}
56 }T;
57 bool check(int id){return T.query(id,t[0],t[1]).rmax+T.query(id,t[1]+1,t[2]-1).sum+T.query(id,t[2],t[3]).lmax>=0;}
58 int solve(){
59     int l=1,r=n,m;
60     while (l<r){
61         m=((l+r)>>1)+1;
62         if (check(m)) l=m; else r=m-1;
63     }
64     return list[l].v;
65 }
66 int main(){
67     read(n);
68     for (int i=1;i<=n;i++) list[i].init(i);
69     sort(list+1,list+n+1,cmp);
70     T.build(T.root[1],1,n);
71     for (int i=1;i<n;i++) T.modify(i+1,list[i].id);
72     for (read(q);q;q--){
73         for (int i=0;i<4;i++) read(t[i]),t[i]=(t[i]+ans)%n+1;
74         sort(t,t+4),ans=solve();
75         printf("%d\n",ans);
76     }
77     return 0;
78 }

 

posted @ 2016-04-24 14:58  chenyushuo  阅读(268)  评论(0编辑  收藏  举报