[BZOJ2653]middle 主席树+二分答案

来源:互联网 发布:linux mysql dump 编辑:程序博客网 时间:2024/06/05 07:32

中位数的题目一定要想到二分答案然后把所有数变成1或-1什么的。。。
先离散化,这样最多只有n个值,然后对于每个值建主席树,>=的设为1,<的设为-1。按照升序建的话每次最多更改一个值,也就是logN个点。
设询问区间[ a, b] [ c, d]为然后二分答案K,现在要求的就是在主席树的第K个版本中(b,c)的和,[ a, b]的最大右子段和,[ c, d]的最大左子段和,三个东西加起来是否大于0。所以线段树中维护sum,maxl,maxr。
maxl,maxr的求法和sum差不多,yy一下。。。
代码:

type  node=record    t,id:longint;  end;  tree=^treenode;  treenode=record    l,r,maxl,maxr,sum:longint;    ls,rs:tree;  end;var  n,m,i,j,last,size:longint;  a:array[0..20010]of node;  b,vsn:array[0..20010]of longint;  tr:array[0..20010]of tree;  q:array[1..4]of longint;function max(x,y:longint):longint;begin  if x>y then exit(x)  else exit(y);end;procedure qs(p,q:longint);var  i,j:longint;  t,mid:node;begin  i:=p;  j:=q;  mid:=a[(p+q)div 2];  repeat    while a[i].t<mid.t do inc(i);    while a[j].t>mid.t do dec(j);    if i<=j then    begin      t:=a[i];      a[i]:=a[j];      a[j]:=t;      inc(i);      dec(j);    end;  until i>j;  if p<j then qs(p,j);  if i<q then qs(i,q);end;procedure px;var  i,j,t:dword;begin  for i:=1 to 4 do    for j:=i+1 to 4 do      if q[i]>q[j]  then begin t:=q[i]; q[i]:=q[j]; q[j]:=t; end;end;procedure update(x:tree);begin  x^.sum:=x^.ls^.sum+x^.rs^.sum;  x^.maxl:=max(x^.ls^.maxl,x^.ls^.sum+x^.rs^.maxl);  x^.maxr:=max(x^.rs^.maxr,x^.rs^.sum+x^.ls^.maxr);end;procedure newx(x:tree;l,t:longint);begin  x^.l:=l;  x^.r:=l;  x^.sum:=t;  x^.maxl:=t;  x^.maxr:=t;  x^.ls:=nil;  x^.rs:=nil;end;procedure build(x:tree;l,r:longint);var  mid:longint;begin  if l=r then  begin    newx(x,l,1);    exit;  end;  x^.l:=l;  x^.r:=r;  mid:=(l+r)div 2;  new(x^.ls);  build(x^.ls,l,mid);  new(x^.rs);  build(x^.rs,mid+1,r);  update(x);end;procedure rebuild(x,y:tree;v:longint);var  mid:longint;begin  if x^.l=x^.r then  begin    newx(y,x^.l,-1);    exit;  end;  y^:=x^;  mid:=(x^.l+x^.r)div 2;  if v<=mid then  begin    new(y^.ls);    rebuild(x^.ls,y^.ls,v);  end  else  begin    new(y^.rs);    rebuild(x^.rs,y^.rs,v);  end;  update(y);end;function getsum(x:tree;l,r:longint):longint;var  mid:longint;begin  if l>r then exit(0);  if (x^.l=l)and(x^.r=r) then exit(x^.sum);  mid:=(x^.l+x^.r)div 2;  if r<=mid then exit(getsum(x^.ls,l,r));  if l>mid then exit(getsum(x^.rs,l,r));  exit(getsum(x^.ls,l,mid)+getsum(x^.rs,mid+1,r));end;function getmaxl(x:tree;l,r:longint):longint;var  mid:longint;begin  if (x^.l=l)and(x^.r=r) then begin exit(x^.maxl);  end;  mid:=(x^.l+x^.r)div 2;  if r<=mid then exit(getmaxl(x^.ls,l,r));  if l>mid then exit(getmaxl(x^.rs,l,r));  if (r>mid)and (l<=mid) then exit(max(getmaxl(x^.ls,l,mid),getsum(x^.ls,l,mid)+getmaxl(x^.rs,mid+1,r)));end;function getmaxr(x:tree;l,r:longint):longint;var  mid:longint;begin  if (x^.l=l)and(x^.r=r) then exit(x^.maxr);  mid:=(x^.l+x^.r)div 2;  if r<=mid then exit(getmaxr(x^.ls,l,r));  if l>mid then exit(getmaxr(x^.rs,l,r));  exit(max(getmaxr(x^.rs,mid+1,r),getsum(x^.rs,mid+1,r)+getmaxr(x^.ls,l,mid)));end;function cal(r:longint):longint;begin  cal:=getsum(tr[vsn[r]],q[2]+1,q[3]-1)+getmaxl(tr[vsn[r]],q[3],q[4])+getmaxr(tr[vsn[r]],q[1],q[2]);end;function solve():longint;var  le,ri,mid:longint;begin  le:=1;  ri:=size+1;  while le<ri do  begin    mid:=(le+ri)div 2;    if cal(mid)<0 then ri:=mid    else le:=mid+1;  end;  exit(le-1);end;begin  readln(n);  for i:=1 to n do  begin    read(a[i].t);    a[i].id:=i;  end;  qs(1,n);  a[0].t:=0;  last:=a[1].t;  b[1]:=last;  a[1].t:=1;  for i:=2 to n do    if a[i].t=last then a[i].t:=a[i-1].t    else begin last:=a[i].t; a[i].t:=a[i-1].t+1; b[a[i].t]:=last; end;  size:=a[n].t;  new(tr[0]);  build(tr[0],1,n);  for i:=1 to n do  begin    if a[i].t>a[i-1].t then vsn[a[i].t]:=i-1;    new(tr[i]);    rebuild(tr[i-1],tr[i],a[i].id);  end;  readln(m);  last:=0;  for i:=1 to m do  begin    for j:=1 to 4 do    begin      read(q[j]);      q[j]:=(q[j]+last)mod n+1;    end;    px;    last:=b[solve()];    writeln(last);  end;end.
0 0