一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
标签:
一个长度为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)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
输入保证满足条件。
Q行依次给出询问的答案。
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 }
标签:
原文地址:http://www.cnblogs.com/ljh2000-jump/p/5800657.html