Problem p02285 (C++)

Buggy submission (status: Runtime Error):
#include <iostream>
#include <string>
using namespace std;

struct Node {
  int val;
  Node *parent;
  Node *left;
  Node *right;
};
Node *nil;

class Tree {
  Node *root;
  void preorder(Node *p) {
    if (p == nil)
      return;
    cout << " " << p->val;
    preorder(p->left);
    preorder(p->right);
  }
  void inorder(Node *p) {
    if (p == nil)
      return;
    inorder(p->left);
    cout << " " << p->val;
    inorder(p->right);
  }
  Node *next_node(Node *z) {
    if (z->left == nil)
      return z;
    return next_node(z->left);
  }
  void delete_node(Node *z) {
    if (z->left == nil && z->right == nil) {
      if (z == root) {
        root = nil;
        return;
      }
      if (z->parent->left == z) {
        z->parent->left = nil;
      } else {
        z->parent->right = nil;
      }
      return;
    }
    if (z->left != nil && z->right != nil) {
      Node *next = next_node(z->right);
      z->val = next->val;
      delete_node(next);
    }
    Node *z_c;
    if (z->left == nil) {
      z_c = z->right;
    }
    if (z->right == nil) {
      z_c = z->left;
    }
    if (z == root) {
      root = z_c;
      return;
    }
    if (z->parent->left == z) {
      z->parent->left = z_c;
    } else {
      z->parent->right = z_c;
    }
    z_c->parent = z->parent;
  }

  Node *find_node(int k) {
    Node *p = root;
    while (p != nil) {
      if (k == p->val)
        return p;
      if (k < p->val) {
        p = p->left;
      } else {
        p = p->right;
      }
    }
    return nil;
  }

public:
  Tree() { root = nil; }
  void insert(int k) {
    Node *n = new Node;
    n->val = k;
    n->left = nil;
    n->right = nil;
    if (root == nil) {
      root = n;
      n->parent = nil;
      return;
    }
    Node *pos = root;
    Node *pos_p;
    while (pos != nil) {
      pos_p = pos;
      if (k < pos->val) {
        pos = pos->left;
        continue;
      }
      pos = pos->right;
    }
    n->parent = pos_p;
    if (k < pos_p->val) {
      pos_p->left = n;
    } else {
      pos_p->right = n;
    }
  }
  void print() {
    inorder(root);
    cout << endl;
    preorder(root);
    cout << endl;
  }
  bool find(int k) {
    Node *z = find_node(k);
    if (z == nil) {
      return false;
    } else {
      return true;
    }
  }
  void del(int k) {
    Node *z = find_node(k);
    delete_node(z);
  }
};

int main() {
  int n;
  cin >> n;
  Tree T;
  for (int i = 0; i < n; i++) {
    string str;
    cin >> str;
    if (str == "print") {
      T.print();
      continue;
    }
    int k;
    cin >> k;
    if (str == "insert") {
      T.insert(k);
      continue;
    }
    if (str == "find") {
      if (T.find(k)) {
        cout << "yes" << endl;
      } else {
        cout << "no" << endl;
      }
      continue;
    }
    if (str == "delete") {
      T.del(k);
    }
  }
  return 0;
}

Fixed submission:
#include <iostream>
#include <string>
using namespace std;

struct Node {
  int val;
  Node *parent;
  Node *left;
  Node *right;
};
Node *nil;

class Tree {
  Node *root;
  void preorder(Node *p) {
    if (p == nil)
      return;
    cout << " " << p->val;
    preorder(p->left);
    preorder(p->right);
  }
  void inorder(Node *p) {
    if (p == nil)
      return;
    inorder(p->left);
    cout << " " << p->val;
    inorder(p->right);
  }
  Node *next_node(Node *z) {
    if (z->left == nil)
      return z;
    return next_node(z->left);
  }
  void delete_node(Node *z) {
    if (z->left == nil && z->right == nil) {
      if (z == root) {
        root = nil;
        return;
      }
      if (z->parent->left == z) {
        z->parent->left = nil;
      } else {
        z->parent->right = nil;
      }
      return;
    }
    if (z->left != nil && z->right != nil) {
      Node *next = next_node(z->right);
      z->val = next->val;
      delete_node(next);
      return;
    }
    Node *z_c;
    if (z->left == nil) {
      z_c = z->right;
    }
    if (z->right == nil) {
      z_c = z->left;
    }
    if (z == root) {
      root = z_c;
      return;
    }
    if (z->parent->left == z) {
      z->parent->left = z_c;
    } else {
      z->parent->right = z_c;
    }
    z_c->parent = z->parent;
  }

  Node *find_node(int k) {
    Node *p = root;
    while (p != nil) {
      if (k == p->val)
        return p;
      if (k < p->val) {
        p = p->left;
      } else {
        p = p->right;
      }
    }
    return nil;
  }

public:
  Tree() { root = nil; }
  void insert(int k) {
    Node *n = new Node;
    n->val = k;
    n->left = nil;
    n->right = nil;
    if (root == nil) {
      root = n;
      n->parent = nil;
      return;
    }
    Node *pos = root;
    Node *pos_p;
    while (pos != nil) {
      pos_p = pos;
      if (k < pos->val) {
        pos = pos->left;
        continue;
      }
      pos = pos->right;
    }
    n->parent = pos_p;
    if (k < pos_p->val) {
      pos_p->left = n;
    } else {
      pos_p->right = n;
    }
  }
  void print() {
    inorder(root);
    cout << endl;
    preorder(root);
    cout << endl;
  }
  bool find(int k) {
    Node *z = find_node(k);
    if (z == nil) {
      return false;
    } else {
      return true;
    }
  }
  void del(int k) {
    Node *z = find_node(k);
    delete_node(z);
  }
};

int main() {
  int n;
  cin >> n;
  Tree T;
  for (int i = 0; i < n; i++) {
    string str;
    cin >> str;
    if (str == "print") {
      T.print();
      continue;
    }
    int k;
    cin >> k;
    if (str == "insert") {
      T.insert(k);
      continue;
    }
    if (str == "find") {
      if (T.find(k)) {
        cout << "yes" << endl;
      } else {
        cout << "no" << endl;
      }
      continue;
    }
    if (str == "delete") {
      T.del(k);
    }
  }
  return 0;
}