码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2653 middle

时间:2016-08-23 20:25:14      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:

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

 

正解:二分答案+主席树+线段树

解题报告:

  这道题看了题解才会做的,的确很神。

  给定一个序列,每次询问,给出一个左区间和一个右区间,保证左区间严格小于右区间,问使得左端点在左区间,右端点在右区间的子序列的中位数最大值。

  显然枚举区间端点的话,复杂度太高。考虑换个思路。我们对于每个询问二分一个答案,看是否可行。我们首先二分一个x,可以把这个区间内大于等于x的标为1,小于x的标为-1,如果区间和大于等于0那么可行,否则不可行。那么如何快速判断呢?每次暴力修改并且求和显然不可行,就必须另辟蹊径。如果我们已经给定了一个比x小的区间的情况,那么若想将其表示为x的情况,则需要把小于x但是为1的全部修改为-1。也就是说,我们需要充分运用以前的修改,不需要每次重新修改。所以我们希望一个数据结构来帮助我们复制一份并且每次修改一段,显然主席树可以胜任。第i棵主席树表示第i小的数的把所有数表示成1、-1的情况,并且维护前缀最大值、后缀最大值、区间和。这样一来我们可以排序之后,从前往后将上次的线段树复制一份,再对于每个i每次修改一下i-1,变成-1,所以每次需要修改一条链。

  这样就可以完美解决了,在区间合并的时候开始出了一点问题,拍了一下才看出来。

 

 

  1 //It is made by jump~
  2 #include <iostream>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <ctime>
  9 #include <vector>
 10 #include <queue>
 11 #include <map>
 12 #include <set>
 13 #ifdef WIN32   
 14 #define OT "%I64d"
 15 #else
 16 #define OT "%lld"
 17 #endif
 18 using namespace std;
 19 typedef long long LL;
 20 const int MAXN = 20011;
 21 const int inf = (1<<30);
 22 int n,ans,cnt,daan,jizhu;
 23 int wen[5],zheng,ql,qr;
 24 int root[MAXN];//每棵主席树的根的编号
 25 struct node{
 26     int lmax,rmax,sum; 
 27     int lson,rson;
 28 }a[MAXN*20],tmp,yuan;
 29 struct Num{
 30     int id,val;
 31 }b[MAXN];
 32 
 33 inline int getint()
 34 {
 35        int w=0,q=0;
 36        char c=getchar();
 37        while((c<0 || c>9) && c!=-) c=getchar();
 38        if (c==-)  q=1, c=getchar();
 39        while (c>=0 && c<=9) w=w*10+c-0, c=getchar();
 40        return q ? -w : w;
 41 }
 42 
 43 inline void update(int root){
 44     a[root].sum=a[a[root].lson].sum+a[a[root].rson].sum;
 45     a[root].lmax=max(a[a[root].lson].lmax, a[a[root].lson].sum+a[a[root].rson].lmax ); 
 46     a[root].rmax=max(a[a[root].rson].rmax, a[a[root].rson].sum+a[a[root].lson].rmax );
 47 }
 48 
 49 inline void build(int l,int r,int &now){
 50     cnt++;  now=cnt;
 51     if(l==r) {
 52     a[now].lmax=a[now].rmax=a[now].sum=1;
 53     return ;
 54     }
 55     int mid=(l+r)/2;
 56     build(l,mid,a[now].lson); build(mid+1,r,a[now].rson);
 57     update(now); 
 58 }
 59 
 60 inline void insert(int last,int pos,int l,int r,int &now){
 61     cnt++; now=cnt;
 62     a[now]=a[last];
 63     if(l==r) {
 64     a[now].lmax=a[now].rmax=a[now].sum=-1;
 65     return ;
 66     }
 67     int mid=(l+r)/2;
 68     if(pos<=mid) insert(a[last].lson,pos,l,mid,a[now].lson);
 69     else insert(a[last].rson,pos,mid+1,r,a[now].rson);
 70     update(now);
 71 } 
 72 
 73 inline bool cmp(Num q,Num qq){ return q.val<qq.val; }
 74 
 75 inline node hebing(node q,node qq){//合并
 76     node xin=yuan;
 77     xin.rmax=max(qq.rmax,qq.sum+q.rmax);
 78     xin.lmax=max(q.lmax,q.sum+qq.lmax);
 79     xin.sum=q.sum+qq.sum;//!!!!!!!
 80     return xin;
 81 }
 82 
 83 inline void query_lmax(int root,int l,int r){//查询前缀最大值
 84     if(ql<=l && r<=qr) {
 85     if(!zheng) tmp=a[root],zheng=1;
 86     else tmp=hebing(tmp,a[root]);       
 87     return ;
 88     }
 89     int mid=(l+r)/2;
 90     if(ql<=mid) query_lmax(a[root].lson,l,mid);
 91     if(qr>mid) query_lmax(a[root].rson,mid+1,r);
 92 }
 93 
 94 inline void query_rmax(int root,int l,int r){//查询后缀最大值
 95     if(ql<=l && r<=qr) {
 96     if(!zheng) tmp=a[root],zheng=1;
 97     else tmp=hebing(tmp,a[root]);       
 98     return ;
 99     }
100     int mid=(l+r)/2;
101     if(ql<=mid) query_rmax(a[root].lson,l,mid);
102     if(qr>mid) query_rmax(a[root].rson,mid+1,r);
103 }
104 
105 inline void query_sum(int root,int l,int r){
106     if(ql>qr) return ;
107     if(ql<=l && r<=qr) {
108     daan+=a[root].sum; return ;
109     }
110     int mid=(l+r)/2;
111     if(ql<=mid) query_sum(a[root].lson,l,mid);
112     if(qr>mid) query_sum(a[root].rson,mid+1,r);
113 }
114 
115 inline bool check(int x){
116     ql=wen[1]; qr=wen[2]; zheng=0; tmp=yuan;
117     query_rmax(root[x],1,n); int nowl=tmp.rmax;
118 
119     ql=wen[3]; qr=wen[4]; zheng=0; tmp=yuan;
120     query_lmax(root[x],1,n); int nowr=tmp.lmax;
121 
122     ql=wen[2]+1; qr=wen[3]-1;
123     daan=0; query_sum(root[x],1,n);//中间一段一定会选入区间
124     int li=nowl+nowr+daan; if(li>=0) return true;
125     return false;
126 }
127 
128 inline void work(){
129     n=getint(); for(int i=1;i<=n;i++) b[i].val=getint(),b[i].id=i;
130     sort(b+1,b+n+1,cmp);
131   
132     build(1,n,root[1]);//初始均为1
133     for(int i=2;i<=n;i++) insert(root[i-1],b[i-1].id,1,n,root[i]);//把前一个设为-1
134 
135     int q=getint(); int l,r;int mid;
136     while(q--) {
137     for(int i=1;i<=4;i++)  wen[i]=getint();
138     for(int i=1;i<=4;i++) wen[i]+=jizhu,wen[i]%=n,wen[i]++;
139     sort(wen+1,wen+4+1);
140     l=1; r=n; 
141     while(l<=r) {
142         mid=(l+r)/2; 
143         if(check(mid)) ans=mid,l=mid+1;
144         else r=mid-1;
145     }
146     jizhu=b[ans].val;
147     printf("%d\n",jizhu);
148     }
149 }
150 
151 int main()
152 {
153   work();
154   return 0;
155 }

 

BZOJ2653 middle

标签:

原文地址:http://www.cnblogs.com/ljh2000-jump/p/5800657.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!