BZOJ2653 middle(二分答案+主席树)
与中位数有关的题二分答案是很常用的trick。二分答案之后,将所有大于它的看成1小于它的看成-1,那么只需要判断是否存在满足要求的一段和不小于0。
由于每个位置是1还是-1并不固定,似乎不是很好算。考虑暴力一点的想法:对于每一种答案预处理。这样查询就很好办了,线段树上每个区间维护最大前缀和后缀和及总和即可。并且可以发现按答案从小到大考虑的话每个位置都是开始一段为1之后为-1,总修改次数只有n次,建主席树即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 20010 int n,m,a[N],b[N],root[N],lastans,cnt=0; vector<int> p[N]; struct data{int l,r,sum,pre,suf; }tree[N<<7]; void build(int &k,int l,int r) { k=++cnt;tree[k].sum=tree[k].pre=tree[k].suf=r-l+1; if (l==r) return; int mid=l+r>>1; build(tree[k].l,l,mid); build(tree[k].r,mid+1,r); } void modify(int &k,int l,int r,int x) { tree[++cnt]=tree[k];k=cnt; tree[k].sum-=2; if (l==r) {tree[k].pre=tree[k].suf=-1;return;} int mid=l+r>>1; if (x<=mid) modify(tree[k].l,l,mid,x); else modify(tree[k].r,mid+1,r,x); tree[k].pre=max(tree[tree[k].l].pre,tree[tree[k].l].sum+tree[tree[k].r].pre); tree[k].suf=max(tree[tree[k].r].suf,tree[tree[k].r].sum+tree[tree[k].l].suf); } int querysum(int k,int l,int r,int x,int y) { if (x>y) return 0; if (l==x&&r==y) return tree[k].sum; int mid=l+r>>1; if (y<=mid) return querysum(tree[k].l,l,mid,x,y); else if (x>mid) return querysum(tree[k].r,mid+1,r,x,y); else return querysum(tree[k].l,l,mid,x,mid)+querysum(tree[k].r,mid+1,r,mid+1,y); } int querypre(int k,int l,int r,int x,int y) { if (l==x&&r==y) return tree[k].pre; int mid=l+r>>1; if (y<=mid) return querypre(tree[k].l,l,mid,x,y); else if (x>mid) return querypre(tree[k].r,mid+1,r,x,y); else return max(querypre(tree[k].l,l,mid,x,mid),querysum(tree[k].l,l,mid,x,mid)+querypre(tree[k].r,mid+1,r,mid+1,y)); } int querysuf(int k,int l,int r,int x,int y) { if (l==x&&r==y) return tree[k].suf; int mid=l+r>>1; if (y<=mid) return querysuf(tree[k].l,l,mid,x,y); else if (x>mid) return querysuf(tree[k].r,mid+1,r,x,y); else return max(querysuf(tree[k].r,mid+1,r,mid+1,y),querysum(tree[k].r,mid+1,r,mid+1,y)+querysuf(tree[k].l,l,mid,x,mid)); } int calc(int k,int a,int b,int c,int d) { return querysum(root[k],1,n,b+1,c-1)+querysuf(root[k],1,n,a,b)+querypre(root[k],1,n,c,d); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj2653.in","r",stdin); freopen("bzoj2653.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) b[i]=a[i]=read(); sort(b+1,b+n+1); int t=unique(b+1,b+n+1)-b; for (int i=1;i<=n;i++) { a[i]=lower_bound(b+1,b+t,a[i])-b; p[a[i]].push_back(i); } build(root[1],1,n); for (int i=2;i<t;i++) { root[i]=root[i-1]; for (int j=0;j<p[i-1].size();j++) modify(root[i],1,n,p[i-1][j]); } m=read(); while (m--) { int q[4]={(read()+lastans)%n,(read()+lastans)%n,(read()+lastans)%n,(read()+lastans)%n}; sort(q,q+4); int l=1,r=t-1,ans=0; while (l<=r) { int mid=l+r>>1; if (calc(mid,q[0]+1,q[1]+1,q[2]+1,q[3]+1)>=0) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",lastans=b[ans]); } return 0; }