Cod sursa(job #227334)

Utilizator MariusMarius Stroe Marius Data 4 decembrie 2008 09:21:57
Problema Zeap Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.13 kb
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>

using namespace std;

const char iname[] = "zeap.in";
const char oname[] = "zeap.out";

#define Min(a, b)  ((a) < (b) ? (a) : (b))
#define Max(a, b)  ((a) > (b) ? (a) : (b))

class Treap {
private:
    class Node {
    public:
        static const int infinity = int(1e9);

        int key, pr, max_val, min_val, min_diff;
        Node *left, *right;

        Node(const int _key) {
            key = _key, pr = rand() + 1, max_val = min_val = key, min_diff = infinity;
            left = right = NULL;
        }

        void update(void) ;
    };

    void insert(Node *&, Node *const &) ;
    void erase(Node *&, const int ) ;
    int  find(Node *, const int );
    void rotleft(Node *&) ;
    void rotright(Node *&) ;
    void balance(Node *&) ;

public:
    Node *R;

    Treap(): R(NULL) {
        srand(unsigned(time(NULL)));
    }

    void insert(const int key) {
        Node *p = new Node(key);
        insert(R, p);
    }

    int erase(const int key) {
        if (!find(R, key))  return 0;
        erase(R, key);
        return 1;
    }

    int find(const int key) {
        return find(R, key);
    }

    int MaxDiff(void) {
        if (!R || (!R->left && !R->right))  return -1;
        return R->max_val - R->min_val;
    }

    int MinDiff(void) {
        if (!R || (!R->left && !R->right))  return -1;
        return R->min_diff;
    }

    void update(Node *&n) {  n->update();  }
};

void Treap::erase(Node *&n, const int key) {        // key e sigur in treap
    if (key < n->key)
        erase(n->left, key);
    else if (key > n->key)
        erase(n->right, key);
    else {
        int cache = ((n->left) ? 1 : 0) + ((n->right) ? 1 : 0);
        if (cache == 2)
            (n->left->pr > n->right->pr) ? rotleft(n) : rotright(n);
        else if (cache == 1)
            (n->left) ? rotleft(n) : rotright(n);
        else
            delete n, n = NULL;

        if (n != NULL)    erase(n, key);
    }
    if (n != NULL)    update(n);
}

void Treap::insert(Node *&n, Node *const &p) {
    if (n == NULL) {
        n = p;
        return ;
    }
    if (p->key < n->key)
        insert(n->left, p);
    else if (p->key > n->key)
        insert(n->right, p);
    balance(n);
}

void Treap::rotleft(Node *&n) {
    Node *p = n->left;  n->left = p->right, p->right = n, update(n), update(p), n = p;
}

void Treap::rotright(Node *&n) {
    Node *p = n->right; n->right = p->left, p->left = n, update(n), update(p), n = p;
}

void Treap::balance(Node *&n) {
    if (n->left && n->pr < n->left->pr)
        rotleft(n);
    else if (n->right && n->pr < n->right->pr)
        rotright(n);
    update(n);
}

int Treap::find(Node *n, const int key) {
    if (n == NULL)  return 0;
    if (key < n->key)   return find(n->left, key);
    if (key > n->key)   return find(n->right, key);
    return 1;
}

void Treap::Node::update(void) {
    max_val = min_val = key;
    if (left)
        max_val = Max(max_val, left->max_val), min_val = Min(min_val, left->min_val);
    if (right)
        max_val = Max(max_val, right->max_val), min_val = Min(min_val, right->min_val);

    min_diff = int(1e9);
    if (left)
        min_diff = Min(min_diff, left->min_diff), min_diff = Min(min_diff, key - left->max_val);
    if (right)
        min_diff = Min(min_diff, right->min_diff), min_diff = Min(min_diff, right->min_val - key);
}

int main(void)
{
    ifstream in(iname);  ofstream out(oname);
    Treap T;
    for (string s, str; getline(in, s); ) {
        istringstream iss(s);
        int n;
        iss >> str;
        if (str == "I")
            iss >> n, T.insert(n);
        else if (str == "S") {
            iss >> n;
            if (!T.erase(n))    out << -1 <<'\n';
        }
        else if (str == "C")
            iss >> n, out << T.find(n) <<'\n';
        else if (str == "MAX")
            out << T.MaxDiff() <<'\n';
        else if (str == "MIN")
            out << T.MinDiff() <<'\n';
    }
    in.close(), out.close();

    return 0;
}