import java.awt.*;
import Point;
class BST
  {
    int N;
    Node head;
    int depth;

    int delay;
    Graphics page;

    void clear(Color c)
      { 
        int h = page.getClipRect().height;
        int w = page.getClipRect().width;
        page.setColor(c);
        page.fillRect(0, 0, w, h);
      }

    BST(int N, int d, int sw, int delay, Graphics page)
      {
        this.page = page;
        this.head = null; this.depth = d; this.delay = delay;
        if (sw == 0)
          for (int i = 0; i < N; i++)
            this.head = insert(this.head, Math.random(), 1);
        if (sw == 1)
          for (int i = 0; i < N; i++)
            this.head = insert(this.head, ((double) i)/((double) N+1), 0);
        System.out.println(N + "-node tree built");
      }
    void maxmin()
      {
        this.delay = 1;
        for (int i = 0; i < 10; i++) 
          {
            head = rotL(head);
            head = rotR(head);
          }
        while (head.r != null)
            head = rotL(head);
        while (head.l != null)
            head = rotR(head);
      }
    void median()
      {
        head = partR(head, .5);
      }
    Node partR(Node h, double v)
      {
        if (h == null) return null;        
        if (h.v > v)
          { if (h.l == null) return h;
            h.l = partR(h.l, v); h = rotR(h); }
        if (h.v < v)
          { if (h.r == null) return h;
            h.r = partR(h.r, v-h.v); h = rotL(h); }
        return h;
      }
    void drawVertex(Point p, Color c)
      { 
        int h = page.getClipRect().height-16;
        int w = page.getClipRect().width-16;
        if (c == Color.white)
             page.setColor(Color.black);
        else page.setColor(Color.lightGray);
        page.fillOval( (int) (w*p.x)+6, (int) (h*p.y)+6, 16, 16);
        page.setColor(c);
        for (int j = 0; j < delay; j++)
          {
            page.fillOval( (int) (w*p.x)+8, (int) (h*p.y)+8, 16, 16);
          }
      }
    void drawEdge(Point p, Point q, Color c)
      { 
        int h = page.getClipRect().height-16;
        int w = page.getClipRect().width-16;
        page.setColor(c);
        page.drawLine( (int) (w*p.x)+16, (int) (h*p.y)+16, 
                         (int) (w*q.x)+16, (int) (h*q.y)+16);
        if (c == Color.lightGray)
          {
            page.drawLine( (int) (w*p.x)+17, (int) (h*p.y)+17, 
                         (int) (w*q.x)+17, (int) (h*q.y)+17);
            page.drawLine( (int) (w*p.x)+15, (int) (h*p.y)+15, 
                         (int) (w*q.x)+15, (int) (h*q.y)+15);
          }
      }
    Node rotL(Node h)
      {
        double offset, lim;
        if (h.r == null) return null;
        lim = 1.0/((double) this.depth+1); offset = .005;
        for (double x = 0; x < lim; x += offset)
          {
            drawEdge(h.pt, h.r.pt, Color.lightGray);
            if (h.r.l != null) drawEdge(h.r.pt, h.r.l.pt, Color.lightGray);
            drawVertex(h.pt, Color.lightGray);
            drawVertex(h.r.pt, Color.lightGray);
            h.pt.y += offset; 
            drawEdge(h.pt, h.r.pt, Color.black);
            if (h.r.l != null) drawEdge(h.r.pt, h.r.l.pt, Color.black);
            if (h.r.l != null) drawVertex(h.r.l.pt, Color.white);
            moveTree(h.l, h, offset);
            h.r.pt.y -= offset; moveTree(h.r.r, h.r, -offset); 
          }
        clear(Color.lightGray); 
        drawTree(head, head);
        Node x = h.r; h.r = x.l; x.l = h; 
        return x;
      }
    Node rotR(Node h)
      {
        double offset, lim;
        if (h.l == null) return null;
        lim = 1.0/((double) this.depth+1); offset = .005;
        for (double x = 0; x < lim; x += offset)
          {
            drawEdge(h.pt, h.l.pt, Color.lightGray);
            if (h.l.r != null) drawEdge(h.l.pt, h.l.r.pt, Color.lightGray);
            drawVertex(h.pt, Color.lightGray);
            drawVertex(h.l.pt, Color.lightGray);
            h.pt.y += offset; 
            drawEdge(h.pt, h.l.pt, Color.black);
            if (h.l.r != null) drawEdge(h.l.pt, h.l.r.pt, Color.black);
            if (h.l.r != null) drawVertex(h.l.r.pt, Color.white);
            moveTree(h.r, h, offset);
            h.l.pt.y -= offset; moveTree(h.l.l, h.l, -offset); 
          }
        clear(Color.lightGray); 
        drawTree(head, head);
        Node x = h.l; h.l = x.r; x.r = h; 
        return x;
      }
    void moveTree(Node h, Node p, double offset)
      {
        double y; 
        if (h == null) return;
        drawVertex(h.pt, Color.lightGray);
        drawVertex(p.pt, Color.lightGray);
        drawEdge(p.pt, h.pt, Color.lightGray);
        h.pt.y += offset; 
        drawEdge(p.pt, h.pt, Color.black);
        drawVertex(h.pt, Color.white);
        drawVertex(p.pt, Color.white);
        moveTree(h.l, h, offset);
        moveTree(h.r, h, offset);
      }
    void drawTree(Node h, Node p)
      {
        if (h == null) return;
        drawEdge(p.pt, h.pt, Color.black);
        drawVertex(h.pt, Color.white);
        drawVertex(p.pt, Color.white);
        drawTree(h.l, h);
        drawTree(h.r, h);
      }
    Node insert(Node h, double v, int d)
      {
        if (h == null) 
          {
            double sy = ((double) d)/((double) this.depth+1);
            Point s = new Point(v, sy);
            return new Node(v, d+1, s);
          }
        double sy = ((double) d+1)/((double) this.depth+1);
        Point s = new Point(v, sy);
        double my = ((double) d)/((double) this.depth+1);
        Point me = new Point(h.v, my);
        if ((h.l == null) && (v < h.v))
          {
            drawEdge(s, me, Color.black);
            drawVertex(me, Color.white);
            drawVertex(s, Color.white);
          }
        if ((h.r == null) && !(v < h.v))
          {
            drawEdge(s, me, Color.black);
            drawVertex(me, Color.white);
            drawVertex(s, Color.white);
          }
        drawVertex(me, Color.red);
        if (v < h.v) 
             h.l = insert(h.l, v, d+1);                
        else h.r = insert(h.r, v, d+1);
        drawVertex(me, Color.white);
        return h;
      }
  }










