POJ 1765 — November Rain

Posted on 四月 12th, 2008.

话说也是攒了好久的题了…今天终于AC了.
是CEOI 2003的一道题,SPOJ和POJ上都有.

一道平衡树的题目,用Splay做到了POJ Pascal组第10,SPOJ Pascal组第12.不过Nxun是POJ Pascal组第6,SPOJ Pascal第9…

题目描述么…看我和hrm的这段聊天记录:

hrm 22:51:49
什么题啊?
Killa.sqybi 22:52:26
就是说…一堆屋顶,给出两个端点的坐标,然后任意两个屋顶不相交或者相连
Killa.sqybi 22:52:31
天上下雨
Killa.sqybi 22:52:39
问每个屋顶能接到多少雨
Killa.sqybi 22:52:44
雨会向下流
Killa.sqybi 22:52:48
就这道题..
hrm 22:53:31
噢。我退化了
hrm 22:53:37
不懂为什么用splay了
hrm 22:53:45
输入是什么啊
Killa.sqybi 22:54:30
第一行是屋顶数n 接下来n行每行四个数 分别是屋顶左右端点的x y坐标
hrm 22:56:11
然后呢?每一滴雨的坐标?
Killa.sqybi 22:56:39
哦..我忘了说
每个单位长度落下一滴雨
hrm 22:56:57
。。。。。
hrm 22:57:39
那直接用面积不就知道每个屋顶接多少雨了么
Killa.sqybi 22:58:02
不是..雨会被上面的屋顶挡住..而且会从上面的屋顶比较矮的那边流下来

嗯,就是这样.然后呢,做法就是,从左边开始,用一条扫描线对每个线段的端点进行扫描.每条线段对应三个事件:第一个是左端点,对应线段进入扫描线上的序列;第二个是线段右端点,对应线段离开;第三个是线段比较低的一端,对应的是向下流水.
然后,因为两条线段的重叠部分,一条总是高于另一条而不会改变(否则就会相交),所以可以用Splay维护一个线段的序列.
最后只要先扫描一遍,同时用一个图记录每条线段的流水情况(流到哪条线段,程序中为了实现方便把边反向),然后进行拓补排序(或者DFS)就可以.

刚才在POJ上AC之后,到SPOJ上死活都TLE.而Nxun在SPOJ上AC的程序,到POJ死活都RE.最后发现了问题,SPOJ是多组数据,而POJ是一组…

{
POJ 1765; SPOJ 86; November Rain
- sqybi’s code
- Splay
- 创建事件点,从左向右扫描,每次维护当前扫描线上所有线段的排序
}
//for my winsty
program pku1765_sqybi;
  const
    nn = 40000;
    e = 1e-6;

  type
    rec = record
      x, p: longint;
    end;
    TSplayTree = object
      root, num: longint;
      data, father: array[1..nn]of longint;
      son: array[0..1, 1..nn]of longint;
      procedure init;
      function height(x, y: longint): real;
      function compare(x, y: longint): boolean;
      procedure rotate(x, w: longint);
      procedure splay(x, y: longint);
      procedure addNode(x, y, z: longint);
      procedure insert(y: longint);
      function find(y: longint): longint;
      procedure delete(y: longint);
      function min: longint;
      function succ(y: longint): longint;
    end;
    TGraph = object
      m: longint;
      head: array[0..nn]of longint;
      adj, next: array[1..nn]of longint;
      procedure init;
      procedure addEdge(x, y: longint);
      procedure dfs(x: longint);
    end;

  var
    n, i, j, top: longint;
    a: array[1..nn, 1..4]of longint;
    b: array[1..nn*3]of rec;
    water, directWater: array[0..nn]of longint;
    tree: TSplayTree;
    graph: TGraph;

  function compare(r1, r2: rec): boolean; //a < b
    var
      x1, x2: longint;
    begin
      if r1.p = 2 then begin
        if a[r1.x, 2] < a[r1.x, 4] then
          x1 := a[r1.x, 1]
        else
          x1 := a[r1.x, 3];
      end
      else
        x1 := a[r1.x, r1.p];
      if r2.p = 2 then begin
        if a[r2.x, 2] < a[r2.x, 4] then
          x2 := a[r2.x, 1]
        else
          x2 := a[r2.x, 3];
      end
      else
        x2 := a[r2.x, r2.p];
      compare := (x1 < x2) or ((x1 = x2) and (r1.p < r2.p));
    end;

  procedure qsort(l, r: longint);
    var
      i, j: longint;
      d, t: rec;
    begin
      i := l;
      j := r;
      d := b[(l+r) div 2];
      repeat
        while compare(b[i], d) do inc(i);
        while compare(d, b[j]) do dec(j);
        if i <= j then begin
          t := b[i];
          b[i] := b[j];
          b[j] := t;
          inc(i);
          dec(j);
        end;
      until i > j;
      if l < j then qsort(l, j);
      if i < r then qsort(i, r);
    end;

  procedure TSplayTree.init;
    begin
      root := 0;
      num := 0;
    end;

  function TSplayTree.height(x, y: longint): real;
    begin
      height := a[x, 2] + (y - a[x, 1]) / (a[x, 3] - a[x, 1]) * (a[x, 4] - a[x, 2]);
    end;

  function TSplayTree.compare(x, y: longint): boolean; //x < y
    var
      t: array[1..4]of longint;
      i, j: longint;
      h1, h2: real;
    begin
      t[1] := a[x, 1];
      t[2] := a[x, 3];
      t[3] := a[y, 1];
      t[4] := a[y, 3];
      for i:=1 to 3 do
        for j:=i+1 to 4 do
          if t[i] > t[j] then begin
            t[i] := t[i] xor t[j];
            t[j] := t[i] xor t[j];
            t[i] := t[i] xor t[j];
          end;
      h1 := height(x, t[2]);
      h2 := height(y, t[2]);
      compare := h1 > h2;
    end;

  procedure TSplayTree.rotate(x, w: longint);
    var
      y: longint;
    begin
      y := father[x];
      son[1-w, y] := son[w, x];
      if son[w, x] <> 0 then
        father[son[w, x]] := y;
      father[x] := father[y];
      if father[y] <> 0 then
        if son[0, father[y]] = y then
          son[0, father[y]] := x
        else
          son[1, father[y]] := x;
      father[y] := x;
      son[w, x] := y;
    end;

  procedure TSplayTree.splay(x, y: longint);
    begin
      while father[x] <> y do begin
        if father[father[x]] <> y then begin
          if father[x] = son[0, father[father[x]]] then begin
            if x = son[0, father[x]] then begin
              rotate(father[x], 1);
              rotate(x, 1);
            end
            else begin
              rotate(x, 0);
              rotate(x, 1);
            end;
          end
          else begin
            if x = son[1, father[x]] then begin
              rotate(father[x], 0);
              rotate(x, 0);
            end
            else begin
              rotate(x, 1);
              rotate(x, 0);
            end;
          end;
        end
        else
          if x = son[0, father[x]] then
            rotate(x, 1)
          else
            rotate(x, 0);
      end;
      if y = 0 then root := x;
    end;

  procedure TSplayTree.addNode(x, y, z: longint);
    begin
      data[num] := z;
      father[num] := y;
      son[0, num] := 0;
      son[1, num] := 0;
    end;

  procedure TSplayTree.insert(y: longint);
    var
      x: longint;
    begin
      if root = 0 then begin
        inc(num);
        root := num;
        addNode(num, 0, y);
        exit;
      end;
      x := root;
      repeat
        if compare(y, data[x]) then begin
          if son[0, x] = 0 then break;
          x := son[0, x];
        end
        else begin
          if son[1, x] = 0 then break;
          x := son[1, x];
        end;
      until false;
      inc(num);
      addNode(num, x, y);
      if compare(y, data[x]) then
        son[0, x] := num
      else
        son[1, x] := num;
      x := num;
      splay(x, 0);
    end;

  function TSplayTree.find(y: longint): longint;
    var
      x: longint;
    begin
      x := root;
      repeat
        if data[x] = y then break;
        if compare(y, data[x]) then
          x := son[0, x]
        else
          x := son[1, x];
      until false;
      find := x;
    end;

  procedure TSplayTree.delete(y: longint);
    var
      x, z: longint;
    begin
      x := find(y);
      splay(x, 0);
      if son[0, x] = 0 then begin
        if son[1, x] = 0 then
          init
        else begin
          root := son[1, x];
          father[son[1, x]] := 0; 
        end;
      end
      else begin
        z := son[0, x];
        while son[1, z] <> 0 do z := son[1, z];
        splay(z, x);
        father[z] := 0;
        root := z;
        son[1, z] := son[1, x];
        if son[1, z] <> 0 then
          father[son[1, z]] := z;
      end;
  end;

  function TSplayTree.min: longint;
    var
      x: longint;
    begin
      min := 0;
      if root = 0 then exit;
      x := root;
      while son[0, x] <> 0 do x := son[0, x];
      splay(x, 0);
      min := data[x];
    end;

  function TSplayTree.succ(y: longint): longint;
    var
      x: longint;
    begin
      x := find(y);
      splay(x, 0);
      x := son[1, x];
      succ := 0;
      if x = 0 then exit;
      while son[0, x] <> 0 do x := son[0, x];
      succ := data[x];
    end;

  procedure TGraph.init;
    begin
      m := 0;
      fillchar(head, sizeof(head), 0);
    end;

  procedure TGraph.addEdge(x, y: longint);
    begin
      inc(m);
      adj[m] := y;
      next[m] := head[x];
      head[x] := m;
    end;

  procedure TGraph.dfs(x: longint);
    var
      temp: longint;
    begin
      water[x] := directWater[x];
      if head[x] = 0 then exit;
      temp := head[x];
      while temp <> 0 do begin
        if water[adj[temp]] = -1 then dfs(adj[temp]);
        water[x] := water[x] + water[adj[temp]];
        temp := next[temp];
      end;
    end;

  begin
    readln(n);
    for i:=1 to n do begin
      readln(a[i, 1], a[i, 2], a[i, 3], a[i, 4]);
      b[i*3-2].x := i; //segment no.
      b[i*3-2].p := 1; //type
      b[i*3-1].x := i;
      b[i*3-1].p := 3;
      if a[i, 2] < a[i, 4] then begin
        b[i*3].x := i;
        b[i*3].p := 2;
      end
      else begin
        b[i*3].x := i;
        b[i*3].p := 2;
      end;
    end;
    qsort(1, n*3);

    tree.init;
    graph.init;
    tree.insert(b[1].x);
    j := 1;
    for i:=2 to n*3 do begin
      if b[i].p <> 2 then begin
        top := tree.min;
        directWater[top] := directWater[top] + (a[b[i].x, b[i].p] - a[b[j].x, b[j].p]);
        j := i;
      end;
      case b[i].p of
        1: tree.insert(b[i].x);
        2: graph.addEdge(tree.succ(b[i].x), b[i].x);
        3: tree.delete(b[i].x);
      end;
    end;

    fillchar(water, sizeof(water), -1);
    graph.dfs(0);

    for i:=1 to n do
      writeln(water[i]);
  end.

阅读(183 次)

Make a Comment

Make A Comment: ( None so far )

blockquote and a tags work here.

Liked it here?
Why not try sites on the blogroll...