#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define ALL(name) name.begin(),name.end()
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 100010

ll N;
vector<double> X, Y;
vector<char> D;

// 移動開始 m 秒後の Ymax/Xmax を求めます O(N)
// isX が true なら Xmax を、そうでなければ Ymax を返します
double GetMax(double m, bool isX) {
    double ret = -DINF;
    REP(i, N) {
        double cur = (isX) ? X[i] : Y[i];
        if(isX) {
            if(D[i] == 'R') { cur += m; }
            else if(D[i] == 'L') { cur -= m; }
        }
        else {
            if(D[i] == 'U') { cur += m; }
            else if(D[i] == 'D') { cur -= m; }
        }
        ret = max(ret, cur);
    }
    return ret;
}
// 移動開始 m 秒後の Ymin/Xmin を求めます O(N)
// isX が true なら Xmin を、そうでなければ Ymin を返します
double GetMin(double m, bool isX) {
    double ret = DINF;
    REP(i, N) {
        double cur = (isX) ? X[i] : Y[i];
        if(isX) {
            if(D[i] == 'R') { cur += m; }
            else if(D[i] == 'L') { cur -= m; }
        }
        else {
            if(D[i] == 'U') { cur += m; }
            else if(D[i] == 'D') { cur -= m; }
        }
        ret = min(ret, cur);
    }
    return ret;
}

// 移動開始 m 秒後の (Xmax - Xmin) * (Ymax - Ymin) を求めます O(N)
double GetArea(double m) {
    double x_max = -DINF;
    double x_min = DINF;
    double y_max = -DINF;
    double y_min = DINF;
    REP(i, N) {
        double cur_x = X[i];
        double cur_y = Y[i];
        if(D[i] == 'U') { cur_y += m; }
        else if(D[i] == 'D') { cur_y -= m; }
        else if(D[i] == 'R') { cur_x += m; }
        else if(D[i] == 'L') { cur_x -= m; }
        x_max = max(x_max, cur_x);
        x_min = min(x_min, cur_x);
        y_max = max(y_max, cur_y);
        y_min = min(y_min, cur_y);
    }
    return (x_max - x_min) * (y_max - y_min);
}

// Ymax/Xmax の減少が止まる（変わらなくなる）位置を求めます
// isX が true なら Xmax の位置を、そうでなければ Ymax の位置を返します
double TriSearchMax1(bool isX) {
    ll lb = 1, ub = 300000000;
    while(ub - lb > 1) {
        ll mid = (lb + ub) / 2;
        double val_mid = GetMax(static_cast<double>(mid), isX);
        double val_prev = GetMax(static_cast<double>(mid - 1), isX);
        double val_next = GetMax(static_cast<double>(mid + 1), isX);
        if(val_prev < val_mid && val_mid < val_next)        { ub = mid; }
        else if(val_prev == val_mid && val_mid < val_next)  { ub = mid; }
        else if(val_prev == val_mid && val_mid == val_next) { ub = mid; }
        else if(val_prev > val_mid && val_mid == val_next)  { lb = mid; ub = mid + 1; break; }
        else if(val_prev > val_mid && val_mid > val_next)   { lb = mid; }
        else if(val_prev > val_mid && val_mid < val_next)   { lb = mid; ub = mid + 1; break; }
    }
    // この時点で lb + 1 = ub
    // lb から 0.5 刻みでチェックして厳密な位置を探る
    double mid = static_cast<double>(lb) - 0.5;
    double val_prev = GetMax(mid, isX);
    REP(i, 4) {
        mid += 0.5;
        double val = GetMax(mid, isX);
        if(val_prev <= val) { return mid - 0.5; }
        val_prev = val;
    }

    return mid;
}

// Ymax/Xmax が増加し始める位置を求めます
// isX が true なら Xmax の位置を、そうでなければ Ymax の位置を返します
double TriSearchMax2(bool isX) {
    ll lb = 1, ub = 300000000;
    while(ub - lb > 1) {
        ll mid = (lb + ub) / 2;
        double val_mid = GetMax(static_cast<double>(mid), isX);
        double val_prev = GetMax(static_cast<double>(mid - 1), isX);
        double val_next = GetMax(static_cast<double>(mid + 1), isX);
        if(val_prev < val_mid && val_mid < val_next)        { lb = mid; }
        else if(val_prev == val_mid && val_mid < val_next)  { lb = mid; ub = mid + 1; break; }
        else if(val_prev == val_mid && val_mid == val_next) { lb = mid; }
        else if(val_prev > val_mid && val_mid == val_next)  { ub = mid; }
        else if(val_prev > val_mid && val_mid > val_next)   { ub = mid; }
        else if(val_prev > val_mid && val_mid < val_next)   { lb = mid; ub = mid + 1; break; }
    }
    // この時点で lb + 1 = ub
    // lb から 0.5 刻みでチェックして厳密な位置を探る
    double mid = static_cast<double>(lb) - 0.5;
    double val_prev = GetMax(mid, isX);
    REP(i, 4) {
        mid += 0.5;
        double val = GetMax(mid, isX);
        if(val_prev < val) { return mid - 0.5; }
        val_prev = val;
    }

    return mid;
}

// Ymin/Xmin の増加が止まる（変わらなくなる）位置を求めます
// isX が true なら Xmin の位置を、そうでなければ Ymin の位置を返します
double TriSearchMin1(bool isX) {
    ll lb = 1, ub = 300000000;
    while(ub - lb > 1) {
        ll mid = (lb + ub) / 2;
        double val_mid = GetMin(static_cast<double>(mid), isX);
        double val_prev = GetMin(static_cast<double>(mid - 1), isX);
        double val_next = GetMin(static_cast<double>(mid + 1), isX);
        if(val_prev < val_mid && val_mid < val_next)        { lb = mid; }
        else if(val_prev < val_mid && val_mid == val_next)  { lb = mid; ub = mid + 1; break; }
        else if(val_prev == val_mid && val_mid == val_next) { lb = mid; }
        else if(val_prev == val_mid && val_mid > val_next)  { ub = mid; }
        else if(val_prev > val_mid && val_mid > val_next)   { ub = mid; }
        else if(val_prev < val_mid && val_mid > val_next)   { lb = mid; ub = mid + 1; break; }
    }
    // この時点で lb + 1 = ub
    // lb から 0.5 刻みでチェックして厳密な位置を探る
    double mid = static_cast<double>(lb) - 0.5;
    double val_prev = GetMin(mid, isX);
    REP(i, 4) {
        mid += 0.5;
        double val = GetMin(mid, isX);
        if(val_prev >= val) { return mid - 0.5; }
        val_prev = val;
    }

    return mid;
}

// Ymin/Xmin が減少し始める位置を求めます
// isX が true なら Xmin の位置を、そうでなければ Ymin の位置を返します
double TriSearchMin2(bool isX) {
    ll lb = 1, ub = 300000000;
    while(ub - lb > 1) {
        ll mid = (lb + ub) / 2;
        double val_mid = GetMin(static_cast<double>(mid), isX);
        double val_prev = GetMin(static_cast<double>(mid - 1), isX);
        double val_next = GetMin(static_cast<double>(mid + 1), isX);
        if(val_prev < val_mid && val_mid < val_next)        { ub = mid; }
        else if(val_prev < val_mid && val_mid == val_next)  { ub = mid; }
        else if(val_prev == val_mid && val_mid == val_next) { ub = mid; }
        else if(val_prev == val_mid && val_mid > val_next)  { lb = mid; ub = mid + 1; break; }
        else if(val_prev > val_mid && val_mid > val_next)   { lb = mid; }
        else if(val_prev < val_mid && val_mid > val_next)   { lb = mid; ub = mid + 1; break; }
    }
    // この時点で lb + 1 = ub
    // lb から 0.5 刻みでチェックして厳密な位置を探る
    double mid = static_cast<double>(lb) - 0.5;
    double val_prev = GetMin(mid, isX);
    REP(i, 4) {
        mid += 0.5;
        double val = GetMin(mid, isX);
        if(val_prev > val) { return mid - 0.5; }
        val_prev = val;
    }

    return mid;
}

// [lb, ub] の中で面積が最小のものを返す
double TriSearchAreaMin(double lb, double ub) {
    if(lb <= 0) { lb = 0.5; }
    ll cnt = 0;
    while(ub - lb > 1.0) {
        double mid = (lb + ub) / 2.0;
        double val_mid = GetArea(mid);
        double val_prev = GetArea(mid - 0.5);
        double val_next = GetArea(mid + 0.5);
        if(val_prev < val_mid && val_mid < val_next)        { ub = mid; }
        else if(val_prev == val_mid && val_mid < val_next)  { lb = mid - 0.5; ub = mid; break; }
        else if(val_prev == val_mid && val_mid == val_next) { lb = mid; ub = mid + 0.5; break; }
        else if(val_prev > val_mid && val_mid == val_next)  { lb = mid; ub = mid + 0.5; break; }
        else if(val_prev > val_mid && val_mid > val_next)   { lb = mid; }
        else if(val_prev < val_mid && val_mid > val_next)   { lb = mid; ub = mid + 0.5; break; }
        // 予防線
        cnt++;
        if(cnt > 100) {
            lb = mid;
            ub = mid + 0.5;
            break;
        }
    }
    // lb から 0.5 刻みでチェックして厳密な位置を探る
    double mid = static_cast<double>(lb) - 0.5;
    double ret = GetArea(mid);
    REP(i, 4) {
        mid += 0.5;
        ret = min(ret, GetArea(mid));
    }

    return ret;
}

double solve() {
    // 以下のタイミングを求める
    //   - Ymax が変わらなくなる位置
    //   - Ymax が再度変わり始める位置
    //   - Ymin が変わらなくなる位置
    //   - Ymin が再度変わり始める位置

    vector<double> cand;
    cand.push_back(TriSearchMax1(false));
    cand.push_back(TriSearchMax2(false));
    cand.push_back(TriSearchMin1(false));
    cand.push_back(TriSearchMin2(false));

    // X についても同様に求める
    cand.push_back(TriSearchMax1(true));
    cand.push_back(TriSearchMax2(true));
    cand.push_back(TriSearchMin1(true));
    cand.push_back(TriSearchMin2(true));

    SORT(cand);
    cand.erase(unique(cand.begin(), cand.end()), cand.end());

    double ret = GetArea(0);
    for(int i = 0; i < cand.size(); ++i) {
        double val = cand[i] - 10.0;
        while(val < cand[i] + 10.0) {
            if(val > 0) {
                ret = min(ret, GetArea(val));
            }
            val += 0.5;
        }
    }
    for(int i = 0; i < cand.size() - 1; ++i) {
        ret = min(ret, TriSearchAreaMin(cand[i], cand[i+1]));
    }

    assert(ret >= 0);
    return ret;
}

signed main() {
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);

    cin >> N;
    X.resize(N);
    Y.resize(N);
    D.resize(N);
    REP(i, N) {
        cin >> X[i] >> Y[i] >> D[i];
    }

    double ans = solve();
    printf("%.10f\n", ans);

    return 0;
}


Measured memory_bytes: 1920