hdu 1166 敌兵布阵 线段树

题目:有n个兵营(n<=50000),一开始所有兵营都有一定数量的人,然后有三种操作:一种是某个兵营加上一定数量的人,一种是某个兵营减去一定数量的人,一种是统计一个区间内的兵营总共有多少人。操作数量不超过40000。

分析:这道题的数据量很大,如果用朴素算法,每次操作的时间复杂度是O(n),由于有50000次操作,肯定会超时,这时就要用线段树来做,每次操作的时间复杂度是O(log n)。

一定要注意的是这题的读入非常坑爹,要控制好各种空格和换行,不然会w到你****。前车之鉴啊!

下面附代码:

var
  w,l,n,x,y,i:longint;
  t:array[1..150000,1..3] of longint;
  s:string;
  r:char;

procedure hehe(d,l,r:longint);
var
  m:longint;
begin
  t[d,1]:=l;
  t[d,2]:=r;
  t[d,3]:=0;
  if l=r then exit;
  m:=(l+r) div 2;
  hehe(d*2,l,m);
  hehe(d*2+1,m+1,r);
end;

procedure work(d,x,y:longint);
var
  m:longint;
begin
  t[d,3]:=t[d,3]+y;
  if t[d,1]=t[d,2] then exit;
  m:=(t[d,1]+t[d,2]) div 2;
  if x<=m
    then work(d*2,x,y)
    else work(d*2+1,x,y);
end;

function count(d,l,r:longint):longint;
var
  m:longint;
begin
  if (t[d,1]=l)and(t[d,2]=r) then exit(t[d,3]);
  m:=(t[d,1]+t[d,2]) div 2;
  if r<=m
    then count:=count(d*2,l,r)
    else if l>m
           then count:=count(d*2+1,l,r)
           else count:=count(d*2,l,m)+count(d*2+1,m+1,r);
end;

begin
  readln(w);
  for l:=1 to w do
  begin
    writeln('Case ',l,':');
    readln(n);
    hehe(1,1,n);
    for i:=1 to n do
    begin
      read(x);
      work(1,i,x);
    end;
    readln;
    s:='';
    read(r);
    while (r<>' ')and(not eoln) do
    begin
      s:=s+r;
      read(r);
    end;
    while s[1]<>'E' do
    begin
      readln(x,y);
      case s[1] of
        'A':work(1,x,y);
        'S':work(1,x,-y);
        'Q':writeln(count(1,x,y));
      end;
      read(r);
      s:='';
      while (r<>' ')and(not eoln) do
      begin
        s:=s+r;
        read(r);
      end;
    end;
    readln;
  end;
end.


你可能感兴趣的:(hdu 1166 敌兵布阵 线段树)