[TyvjP1474]二维线段树区间更新+查询

每个输入文件有多行。
第一行,一个数n,表示鼹鼠的范围。
以后每一行开头都有一个数m,表示不同的操作:
m=1,那么后面跟着3个数x,y,k(0<=x,y<n),表示在点(x,y)处新出现了k只鼹鼠;
m=2,那么后面跟着4个数x1,y1,x2,y2(0<=x1<=x2<n,0<=y1<=y2<n),表示询问矩形(x1,y1)-(x2,y2)内的鼹鼠数量;
m=3,表示老师来了,不能玩了。保证这个数会在输入的最后一行。
询问数不会超过10000,鼹鼠数不会超过maxlongint。

n<=1024


测试数据 #1: Accepted, time=0ms, mem=98806KB, score=10
测试数据 #2: Accepted, time=124ms, mem=98806KB, score=10
测试数据 #3: Accepted, time=15ms, mem=98806KB, score=10
测试数据 #4: Accepted, time=15ms, mem=98806KB, score=10
测试数据 #5: Accepted, time=109ms, mem=98806KB, score=10
测试数据 #6: Accepted, time=0ms, mem=98806KB, score=10
测试数据 #7: Accepted, time=62ms, mem=98806KB, score=10
测试数据 #8: Accepted, time=31ms, mem=98806KB, score=10
测试数据 #9: Accepted, time=15ms, mem=98802KB, score=10
测试数据 #10: Accepted, time=140ms, mem=98806KB, score=10
Time = 511ms Mem = 98806KB Score= 100


这道题虽然是单点,但我写的是区间。(其实用树状数组做更快……只是用来试模板= =)

二维线段树注意以下几个方面:

  • X树更新时时要到底到叶节点(因为X树不能lazy),但查询时不用查到叶节点(= =因此tle了若干次)。
  • y树可以lazy,方法和普通线段树一样。
  • 二维线段树的内存占用= =
  • mid取得是xl xr,而不是要查询的区间x1、x2

Code

program segtree2D;

//Accepted

type
 rec=record
   xl,xr,yl,yr:integer;
   add,sum:longint;
 end;

Var
 f:array[0..3100,0..3100] of rec;
 n,m,i,j,x,y,k,x1,x2,y1,y2,op,top:longint;

Function mmin(a,b:longint):longint;inline;begin if a<b then exit(a);exit(b); end;
Function mmax(a,b:longint):longint;inline;begin if a>b then exit(a);exit(b); end;

Procedure buildY(p,q:longint);
var
 mid:longint;
  begin
  if q>top then top:=q;
  if f[p,q].yl=f[p,q].yr then exit;
  mid:=(f[p,q].yl+f[p,q].yr) div 2;
  with f[p,q*2] do
    begin
    xl:=f[p,q].xl;
    xr:=f[p,q].xr;
    yl:=f[p,q].yl;
    yr:=mid;
  end;
  buildy(p,q*2);
  with f[p,q*2+1] do
    begin
    xl:=f[p,q].xl;
    xr:=f[p,q].xr;
    yl:=mid+1;
    yr:=f[p,q].yr;
  end;
  buildY(p,q*2+1);
end;

Procedure buildx(P:longint);
var
 mid:longint;
  begin
  f[p,1].yl:=0;f[p,1].yr:=n-1;
  buildy(p,1);
  if f[p,1].xl=f[p,1].xr then exit;
  mid:=(f[p,1].xl+f[p,1].xr) div 2;
  with f[p*2,1] do
    begin
    xl:=f[p,1].xl;
    xr:=mid;
  end;
  buildx(p*2);
  with f[p*2+1,1] do
    begin
    xl:=mid+1;
    xr:=f[p,1].xr;
  end;
  buildx(p*2+1);
end;

Procedure pushdown(p,q:longint);
  begin
  if p>top then exit;
  //writeln('push down ',p,' ',q,' #:',f[p,q].add);
  if q*2<=top then begin
  inc(f[p,q*2].sum,(f[p,q*2].yr-f[p,q*2].yl+1)*f[p,q].add);
  inc(f[p,q*2].add,f[p,q].add);   end;
  if q*2+1<=top then begin
  inc(f[p,q*2+1].sum,(f[p,q*2+1].yr-f[p,q*2+1].yl+1)*f[p,q].add);
  inc(f[p,q*2+1].add,f[p,q].add);     end;
  f[p,q].add:=0;
end;

Procedure addy(p,q,x1,x2,y1,y2,k:longint);
var
 mid:longint;
  begin
  pushdown(p,q);
  with f[p,q] do
    begin
    if (yl=y1) and (yr=y2) then
      begin
      inc(sum,(yr-yl+1)*(x2-x1+1)*k);
      inc(add,k*(x2-x1+1));
      exit;
    end;
    mid:=(yl+yr) shr 1;
    if y1<=mid then addy(p,q*2,x1,x2,y1,mmin(y2,mid),k);
    if y2>mid then addy(p,q*2+1,x1,x2,mmax(y1,mid+1),y2,k);
    f[p,q].sum:=f[p,q*2].sum+f[p,q*2+1].sum;
  end;

end;

Procedure Addx(P,x1,y1,x2,y2,k:longint);
var
 mid:longint;
  begin
  Addy(p,1,x1,x2,y1,y2,k);
  if (f[p,1].xr=f[p,1].xl) then exit;
  with f[p,1] do mid:=(xl+xr) div 2;
  if x1<=mid then Addx(p*2,x1,y1,mmin(x2,mid),y2,k);
  if x2>mid then Addx(p*2+1,mmax(mid+1,x1),y1,x2,y2,k);
end;

Function getsumy(p,q,x1,x2,y1,y2:longint):longint;
var
 mid:longint;
  begin
  pushdown(p,q);  getsumy:=0;
  with f[p,q] do
    if (yl=y1) and (yr=y2) then
      begin
      //writeln('straight got!',yl,' ',yr,' ',f[p,q].sum);
      exit(f[p,q].sum)
    end
    else
      begin
      mid:=(yl+yr) shr 1;
      if y1<=mid then inc(getsumy,getsumy(p,q*2,x1,x2,y1,mmin(y2,mid)));
      if y2>mid then inc(getsumy,getsumy(p,q*2+1,x1,x2,mmax(y1,mid+1),y2));
    end;
  //writeln('getsumY',p,' ',x1,',',y1,' | ',x2,',',y2,' =',getsumy);
end;

Function getsumX(p,x1,y1,x2,y2:longint):longint;
var
 mid:longint;
  begin
  getsumx:=0;
  with f[p,1] do
    if (xl=x1) and (xr=x2) then
      inc(getsumx,getsumy(p,1,x1,x2,y1,y2))
    else
      begin
      mid:=(xl+xr) shr 1;
      if x1<=mid then inc(getsumx,getsumx(p*2,x1,y1,mmin(x2,mid),y2));
      if x2>mid then inc(getsumx,getsumx(p*2+1,mmax(mid+1,x1),y1,x2,y2));
    end;
  //writeln('getsumX',p,' ',x1,',',y1,' | ',x2,',',y2,' =',getsumx);
end;

Procedure init(N:longint);
  begin
  with f[1,1] do
    begin
    xl:=0;
    xr:=n-1;
  end;
  Buildx(1);
end;

  begin
  readln(n);
  init(n);
  top:=0;
  while true do
    begin
    read(op);
    case op of
      1:
        begin
        readln(x,y,k);
        AddX(1,x,y,x,y,k);
      end;
      2:
        begin
        readln(x1,y1,x2,y2);
        writeln(getsumX(1,x1,y1,x2,y2));
      end;
      3:
        halt;
    end;
 end;
end.
原文地址:https://www.cnblogs.com/htfy/p/3073793.html