2653: middle
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1770 Solved: 990
[ Submit][ Status][ Discuss]
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
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
今天颓了一下午这道题,找错找到我吃了shi一样。
结果打错了一个字母。(滑稽)
然后去跟tyb大神play ping-pong了
现在才写blog
题解:
一开始没想到二分,然后去看了路标。
知道是二分+主席树
二分答案,如果取件内大于ans的+1,否则的话-1
如果总和大于等于0的话证明ans还可以大。
至于check,我们可以对于每个-1建一棵树
对于[a,b]这一段我们找最大的后缀和,[c,d]这段找最小的前缀和。
b,c这一段的和肯定是不变的所以直接加上就好了
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 200020
#define M 8005000
struct xy{int o,num;}a[N];
int cmp(xy a,xy b){return a.num < b.num;}
int root[N],n,q;
int ls[M],rs[M],lm[M],rm[M],sum[M];
int cnt;
void push_up(int k){
sum[k] = sum[ls[k]] + sum[rs[k]];
lm[k] = max(lm[ls[k]],sum[ls[k]] + lm[rs[k]]);
rm[k] = max(rm[rs[k]],sum[rs[k]] + rm[ls[k]]);
}
void build(int &rt,int l,int r){
rt = ++ cnt;
if (l == r) {
lm[rt] = rm[rt] = sum[rt] = 1;
return;
}
int m = l + r >> 1;
build(ls[rt],l,m);
build(rs[rt],m + 1,r);
push_up(rt);
}
void update(int last,int l,int r,int &rt,int k,int val){
rt = ++ cnt;
ls[rt] = ls[last],rs[rt] = rs[last];
if (l == r){
sum[rt] = lm[rt] = rm[rt] = val;
return;
}
int m = l + r >> 1;
if (k <= m) update(ls[last],l,m,ls[rt],k,val);
else update(rs[last],m + 1,r,rs[rt],k,val);
push_up(rt);
}
int qall(int rt,int l,int r,int x,int y){
if (l == x && r == y) return sum[rt];
int m = l + r >> 1;
if (y <= m) return qall(ls[rt],l,m,x,y);
else if (x > m) return qall(rs[rt],m + 1,r,x,y);
else return qall(ls[rt],l,m,x,m) + qall(rs[rt],m + 1,r,m + 1,y);
}
int ql(int rt,int l,int r,int x,int y){
if (l == x && r == y) return lm[rt];
int m = l + r >> 1;
if (y <= m) return ql(ls[rt],l,m,x,y);
else if (x > m) return ql(rs[rt],m + 1,r,x,y);
else return max(ql(ls[rt],l,m,x,m),qall(ls[rt],l,m,x,m) + ql(rs[rt],m + 1,r,m + 1,y));
}
int qr(int rt,int l,int r,int x,int y){
printf("%d %d %d %d %d %d\n",rt,l,r,x,y,rm[rt]);
system("pause");
if (l == x && r == y) return rm[rt];
int m = l + r >> 1;
if (y <= m) return qr(ls[rt],l,m,x,y);
else if (x > m) return qr(rs[rt],m + 1,r,x,y);
else return max(qr(rs[rt],m + 1,r,m + 1,y),qall(rs[rt],m + 1,r,m + 1,y) + qr(ls[rt],l,m,x,m));
}
int check(int k,int a,int b,int c,int d){
//printf("%d %d %d %d\n",a,b,c,d);
int ret = 0;
if (c > b + 1) ret = qall(root[k],0,n - 1,b + 1,c - 1);
//printf("%d ",ret);
ret += ql(root[k],0,n - 1,c,d);
// printf("%d ",ret);
ret += qr(root[k],0,n - 1,a,b);
// printf("%d\n",ret);
return ret >= 0;
}
int main(){
scanf("%d",&n);
for (int i = 0;i < n;i ++){
a[i].o = i;
scanf("%d",&a[i].num);
}
sort(a,a + n,cmp);
build(root[0],0,n - 1);
for (int i = 1;i < n;i ++) update(root[i - 1],0,n - 1,root[i],a[i - 1].o,-1);
//for(int i=1;i<=n;i++) printf("%d\n",root[i]);
scanf("%d",&q);
int ans = 0,p[4];
while (q --){
scanf("%d%d%d%d",&p[0],&p[1],&p[2],&p[3]);
for (int i = 0;i < 4;i ++) p[i] = (ans + p[i]) % n;
sort(p,p + 4);
int l = 0,r = n,mid;
while (l < r - 1){
mid = l + r >> 1;
if (check(mid,p[0],p[1],p[2],p[3])) l = mid;
else r = mid;
}
ans = a[l].num;
printf("%d\n",ans);
}
return 0;
}