BZOJ 1588 BZOJ 1503 平衡数splay

虽然去年11月就会splay了..

不过前天实战一个splay好像写跪了?

还有6天就省选了..就复习了一下..

关于BZOJ1588

是一个学平衡树都会写的一题...

插入一个.求前序,求后继,找一个最小的..

看了discuss发现貌似有几个点最后会少一行=-  =

弄成while循环就好啦 少掉的算0..

代码略丑

var
  l,r,fa,a:array[0..100000] of longint;
  root,ans,n,i,x:longint;
procedure zig(x:longint);
  var
    y,z:longint;
  begin
    y:=fa[x];z:=fa[y];
	if r[x]<>0 then
	  begin
	    l[y]:=r[x];
		fa[r[x]]:=y;
	  end
	else
	  l[y]:=0;
    fa[y]:=x;r[x]:=y;
	if root=y then begin root:=x;exit;end;
	fa[x]:=z;if l[z]=y then l[z]:=x else r[z]:=x;
  end;
procedure zag(x:longint);
  var
    y,z:longint;
  begin
    y:=fa[x];z:=fa[y];
	if l[x]<>0 then
	  begin
	    r[y]:=l[x];
		fa[l[x]]:=y;
	  end
	else
	  r[y]:=0;
	fa[y]:=x;l[x]:=y;
	if root=y then begin root:=x;exit;end;
	fa[x]:=z;if l[z]=y then l[z]:=x else r[z]:=x;
  end;
procedure splay(k:longint);
  begin
    while k<>root do
	  if (l[fa[k]]=k) then
	    if (fa[k]=root) then zig(k)
		else
		  if (l[fa[fa[k]]]=fa[k]) then
		    begin
			  zig(fa[k]);zig(k);
			end
		  else
		    begin
			  zig(k);zag(k);
			end
	  else
	    if (fa[k]=root) then zag(k)
		else
		  if (r[fa[fa[k]]]=fa[k]) then
		    begin
			  zag(fa[k]);zag(k);
			end
		  else
		    begin
			  zag(k);zig(k);
			end;
	root:=k;fa[k]:=0;
  end;
		
procedure add(k:longint);
  var
    i,j:longint;
  begin
    i:=root;
    if i=0 then
	  begin
	    root:=k;
		exit;
	  end;
	j:=i;
	while i<>0 do
	  begin
	    j:=i;
		if a[i]<=a[k] then i:=r[i] else i:=l[i];
	  end;
	if a[j]<=a[k] then r[j]:=k else l[j]:=k;
	fa[k]:=j;
	splay(k);
  end;
function find(k:longint):longint;
  var
    i,ans1,ans2:longint;
  begin
    i:=l[k];ans1:=-1;
	while (r[i]<>0) and (i<>0) do
	  i:=r[i];
	if i<>0 then ans1:=abs(a[i]-a[k]);
	i:=r[k];ans2:=-1;
	while (l[i]<>0) and (i<>0) do
	  i:=l[i];
	if i<>0 then ans2:=abs(a[i]-a[k]);
	if (ans1=-1) and (ans2=-1) then exit(a[k]);
	if ans1=-1 then exit(ans2);
	if ans2=-1 then exit(ans1);
	if ans1<ans2 then exit(ans1) else exit(ans2);
  end;
begin
  fillchar(l,sizeof(l),0);
  fillchar(r,sizeof(r),0);
  fillchar(fa,sizeof(fa),0);
  readln(n);ans:=0;i:=0;
  while not eof do
    begin
	  i:=i+1;
	  readln(a[i]);
	  add(i);
	  x:=find(i);
	  ans:=ans+x;
	end;
  if i<n then
    while i<>n do
	  begin
	    i:=i+1;
		a[i]:=0;
		add(i);
		ans:=ans+find(i);
	  end;
  writeln(ans);
end.

1503不算难..

插入 size 找第K大 删除

说一下lazy标记  一路插入  一路下方标记

增加只要把根节点的lazy加就行了

减少工资就要lazy剪掉,然后还要做一个删除操作...

删除操作是每次从根找最小值..然后判断是否比min小 小就删掉(因为是最小的,删除很方便)

一路找,一路下方标记...直到最小的大于等于min

找第K大 直接找就行了...利用size

注意...一开始工资就比min低的人不算在离开公司的人内......

这个代码更丑了。。速度还奇慢=- = 别人几百ms 我要2000msQAQ

Orz purpleslz大神!!

省选加油!

var
  size,a,l,r,fa,lazy:array[0..100100] of longint;
  ans,root,i,n,min,x,j,sum:longint;
  c:char;
procedure zig(x:longint);
  var
    y,z:longint;
  begin
    y:=fa[x];z:=fa[y];
	a[y]:=a[y]+lazy[y];a[x]:=a[x]+lazy[y]+lazy[x];inc(lazy[r[y]],lazy[y]);
	inc(lazy[l[x]],lazy[x]+lazy[y]);inc(lazy[r[x]],lazy[x]+lazy[y]);
	lazy[x]:=0;lazy[y]:=0;size[x]:=size[y];size[y]:=size[r[y]]+size[r[x]]+1;
	if r[x]<>0 then
	  begin
	    l[y]:=r[x];
		fa[r[x]]:=y;
	  end
	else l[y]:=0;
	fa[y]:=x;fa[x]:=z;r[x]:=y;
	if y=root then begin root:=x;exit;end;
	if l[z]=y then l[z]:=x else r[z]:=x;
  end;
procedure zag(x:longint);
  var
    y,z:longint;
  begin
    y:=fa[x];z:=fa[y];
	a[y]:=a[y]+lazy[y];a[x]:=a[x]+lazy[y]+lazy[x];inc(lazy[l[y]],lazy[y]);
	inc(lazy[l[x]],lazy[x]+lazy[y]);inc(lazy[r[x]],lazy[x]+lazy[y]);
	lazy[x]:=0;lazy[y]:=0;size[x]:=size[y];size[y]:=size[l[y]]+size[l[x]]+1;
	if l[x]<>0 then
	  begin
	    r[y]:=l[x];
		fa[l[x]]:=y;
	  end
	else r[y]:=0;
	fa[y]:=x;fa[x]:=z;l[x]:=y;
	if y=root then begin root:=x;exit;end;
	if l[z]=y then l[z]:=x else r[z]:=x;
  end;
	
procedure splay(k:longint);
  begin
    while k<>root do
	  if l[fa[k]]=k then
	    if fa[k]=root then zig(k)
		else
		  if l[fa[fa[k]]]=fa[k] then 
		    begin
			  zig(fa[k]);zig(k);
			end
	      else
		    begin
			  zig(k);zag(k);
		    end
	  else
	    if fa[k]=root then zag(k)
		else
		  if r[fa[fa[k]]]=fa[k] then
		    begin
			  zag(fa[k]);zag(k);
			end
		  else
		    begin
			  zag(k);zig(k);
			end;
	fa[k]:=0;size[0]:=0;l[0]:=0;fa[0]:=0;r[0]:=0;lazy[0]:=0;
  end;
procedure add(k:longint);
  var
    i,j:longint;
  begin
    i:=root;size[k]:=1;
	if root=0 then
	  begin
	    root:=k;
		exit;
	  end;
	while i<>0 do
	  begin
	    j:=i;
		size[i]:=size[i]+1;
		inc(lazy[l[i]],lazy[i]);
		inc(lazy[r[i]],lazy[i]);
		a[i]:=a[i]+lazy[i];
		lazy[i]:=0;
		if a[k]<a[i] then i:=l[i] else i:=r[i];
	  end;
	fa[k]:=j;if a[k]<a[j] then l[j]:=k else r[j]:=k;
	splay(k);
  end;
procedure del;
  var
    i,J:longint;
	flag:boolean;
  begin
    flag:=true;
    while flag do
      begin
	    i:=root;
	    if root=0 then exit;
	    while i<>0 do
	      begin
		    j:=i;
		    inc(lazy[l[i]],lazy[i]);
		    inc(lazy[r[i]],lazy[i]);
		    a[i]:=a[i]+lazy[i];
			lazy[i]:=0;
			size[i]:=size[i]-1;
		    i:=l[i];
		  end;
		i:=j;
	    if  a[i]<min then
	      if i<>root then
	        begin
		      fa[r[i]]:=fa[i];
		      l[fa[i]]:=r[i];
			  ans:=ans+1;
		    end
	      else
	        begin
		      root:=r[i];
		      fa[r[i]]:=0;
			  ans:=ans+1;
		    end
		else 
		  begin
		    flag:=false;
	        i:=root;
	        if root=0 then exit;
	        while i<>0 do
	          begin
			    size[i]:=size[i]+1;
		        i:=l[i];
		      end;
		  end;
	  end;
  end;
function find(x:longint):longint;
  var
    i,sum:longint;
  begin
    i:=root;
	if root=0 then exit(-1);
	if (X<=0) or (root=0) then exit(-1);
	sum:=0;
	while sum<x do
	  begin
		inc(lazy[l[i]],lazy[i]);
		inc(lazy[r[i]],lazy[i]);
		a[i]:=a[i]+lazy[i];
		lazy[i]:=0;
		if (size[l[i]]+1+sum)=x then 
		  begin
		    splay(i);
			exit(a[i]);
		  end;
		if (size[l[i]]+1+sum)<x then
		  begin
		    sum:=sum+size[l[i]]+1;
			i:=r[i];
			continue;
		  end;
		i:=l[i];
	  end;
	writeln('error');
  end;
		
begin
  readln(n,min);ans:=0;sum:=0;
  for i:=1 to n do
    begin
	  read(c);
	  readln(x);
	  if c='I' then if x>=min then begin sum:=sum+1;a[sum]:=x;add(sum);end;
	  if c='A' then inc(lazy[root],x);
	  if c='S' then begin dec(lazy[root],x);del;end;
	  if c='F' then begin writeln(find(size[root]-x+1));end;
	end;
  writeln(ans);
end.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值