您的位置:首页 > 其它

bzoj 2653 二分答案+可持久化线段树

2014-04-18 14:09 453 查看
  首先离散化,然后我们知道如果对于一个询问的区间[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: