bzoj 2653 二分答案+可持久化线段树
首先离散化,然后我们知道如果对于一个询问的区间[l1,r1],[l2,r2],我们二分到一个答案x,将[l1,r2]区间中的元素大于等于x的设为1,其余的设为-1,那么如果[l1,r1]的最大右区间和加上[r1,l2]的区间和加上[l2,r2]的最大左区间和大于等于0,那么最大的中位数一定大于等于x。因为这个区间中大于等于x的数量超过了一半,那么我们可以二分答案,然后判断最大的合法(见上文)区间和是否大于等于0。
那么对于每个我们二分的值的区间-1,1情况我们不能建立n颗线段树,我们可以建立可持久化线段树来维护这个,最开始的初始值都为1,设rot[x]为二分的值为x的时候区间的1,-1情况的线段树,可以由rot[x-1]这颗线段树继承过来。
反思:之前写的可持久化线段树都是建立的权值线段树,这次是用线段树维护区间值的,而且之前对于rot[x]只会有一次插入,这道题的rot[x]可能会有多次插入,在这里纠结了半天。还有我就是最后输出的是adr[ans],但是前面强制在线的时候我加的是ans,忘了改了= =。
/************************************************************** Problem: 2653 User: BLADEVIL Language: C++ Result: Accepted Time:2012 ms Memory:18196 kb ****************************************************************/ //By BLADEVIL #include <cstdio> #include <cstring> #include <algorithm> #define maxn 50010 using namespace std; struct rec { int key,ans,num; rec() { key=ans=num=0; } }a[maxn]; struct segment { int left,right,maxr,maxl,sum; int son[2]; segment() { left=right=maxr=maxl=sum=0; memset(son,0,sizeof son); } }t[12*maxn]; int n,m,tot; int rot[maxn],adr[maxn]; bool cmp1(rec x,rec y) { return x.ans<y.ans; } bool cmp2(rec x,rec y) { return x.num<y.num; } void update(int x) { t[x].sum=t[t[x].son[0]].sum+t[t[x].son[1]].sum; t[x].maxl=max(t[t[x].son[0]].sum+t[t[x].son[1]].maxl,t[t[x].son[0]].maxl); t[x].maxr=max(t[t[x].son[1]].sum+t[t[x].son[0]].maxr,t[t[x].son[1]].maxr); } void build(int &x,int l,int r) { if (!x) x=++tot; t[x].left=l; t[x].right=r; if (l==r) { t[x].sum=t[x].maxl=t[x].maxr=1; return ; } int mid=t[x].left+t[x].right>>1; build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r); update(x); } void insert(int &x,int rot,int y) { if (!x) x=++tot; t[x].left=t[rot].left; t[x].right=t[rot].right; if (t[x].left==t[x].right) { t[x].sum=t[x].maxl=t[x].maxr=-1; return ; } int mid=t[x].left+t[x].right>>1; if (y>mid) { if (!t[x].son[0]) t[x].son[0]=t[rot].son[0]; if (t[x].son[1]==t[rot].son[1]) t[x].son[1]=0; insert(t[x].son[1],t[rot].son[1],y); } else { if (!t[x].son[1]) t[x].son[1]=t[rot].son[1]; if (t[x].son[0]==t[rot].son[0]) t[x].son[0]=0; insert(t[x].son[0],t[rot].son[0],y); } update(x); } segment combine(segment x,segment y) { segment ans; ans.sum=x.sum+y.sum; ans.maxl=max(x.sum+y.maxl,x.maxl); ans.maxr=max(y.sum+x.maxr,y.maxr); return ans; } segment query(int x,int l,int r) { if ((t[x].left==l)&&(t[x].right==r)) return t[x]; int mid=t[x].left+t[x].right>>1; if (l>mid) return query(t[x].son[1],l,r); else if (r<=mid) return query(t[x].son[0],l,r); else return combine(query(t[x].son[0],l,mid),query(t[x].son[1],mid+1,r)); } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[a[i].num=i].ans); sort(a+1,a+1+n,cmp1); int sum=1,cur=a[1].ans; adr[1]=a[1].ans; for (int i=1;i<=n;i++) if (a[i].ans==cur) a[i].key=sum; else a[i].key=++sum,adr[sum]=cur=a[i].ans; //sort(a+1,a+1+n,cmp2); //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("\n"); build(rot[0],1,n); for (int i=1;i<=n;i++) insert(rot[a[i].key],rot[a[i].key-1],a[i].num); //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d %d\n",i,t[i].left,t[i].right,t[i].son[0],t[i].son[1],t[i].maxl,t[i].maxr); //for (int i=1;i<=n;i++) printf("%d ",adr[i]); printf("\n"); scanf("%d",&m); int ans=0; while (m--) { int ask[5]; for (int i=1;i<=4;i++) scanf("%d",&ask[i]); for (int i=1;i<=4;i++) ask[i]=(ask[i]+adr[ans])%n+1; ans=0; sort(ask+1,ask+5); int l=1,r=n; while (l<=r) { int mid=l+r>>1,TOT=0; //printf("%d %d %d\n",l,r,a[mid].key); //printf("%d %d\n",l,r); segment a1=query(rot[a[mid].key-1],ask[1],ask[2]),a2=query(rot[a[mid].key-1],ask[3],ask[4]); if (ask[2]+1<=ask[3]-1) TOT=query(rot[a[mid].key-1],ask[2]+1,ask[3]-1).sum; //printf("%d\n",TOT); TOT+=a1.maxr+a2.maxl; //printf("%d\n",TOT); //printf("%d\n",a1.maxr); if (TOT>=0) ans=a[mid].key,l=mid+1; else r=mid-1; } printf("%d\n",adr[ans]); } return 0; }