#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

using namespace std;

#define INP "solve"
#define OUT "solve"

const long long INF_LL = 4e18;
const int INF = 1e9 + 100;
const int MOD = 1e9 + 7;
const int Base = 311;
const long double EPS = 1e-10;
const int BLOCK = 550;
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());

void open_file() {
    #ifdef THEMIS
        freopen(INP ".inp","r",stdin);
        freopen(OUT ".out","w",stdout);
    #endif // THEMIS
}

const int maxN = 1e5 + 100;

struct DinicFlow { ///Base 0-th, The vertices are numbered from 0 to n - 1
    const long long oo = INF_LL; ///if flow > int, use long long
    int n, numEdge;
    vector <int> point, next, head, Dist, work;
    vector <long long> flow, cap; ///if flow > int, use long long

    DinicFlow(int _n = 0) {
        n = _n; numEdge = 0;
        head.assign(n + 7, -1);
        work.assign(n + 7, -1);
        Dist.assign(n + 7, 0);
    }

    void add_Edge(int u, int v, long long c1, long long c2 = 0) {///if flow > int, use long long c1, c2
        ///u -> v: c1
        point.push_back(v); flow.push_back(0); cap.push_back(c1); next.push_back(head[u]); head[u] = numEdge++;
        ///v -> u: c2
        point.push_back(u); flow.push_back(0); cap.push_back(c2); next.push_back(head[v]); head[v] = numEdge++;
    }

    bool BFS(int s, int t) { ///check has path from s to t
        queue <int> Q;
        for (int i = 0; i <= n; i++) Dist[i] = -1;
        Dist[s] = 0;
        Q.push(s);
        while ((int)Q.size() != 0) {
            int u = Q.front(); Q.pop();
            for (int i = head[u]; i >= 0; i = next[i]) {
                int v = point[i];
                if (flow[i] < cap[i] && Dist[v] == -1) {
                    Dist[v] = Dist[u] + 1;
                    if (v == t) return true;
                    Q.push(v);
                }
            }
        }
        return false;
    }

    long long DFS(int s, int t, long long f) { ///if flow > int, use long long
        if (f == 0) ///Min F always >= 0 so if f = 0 break recursive
            return f;
        if (s == t)
            return f;
        for (int &i = work[s]; i >= 0; i = next[i]) { ///&i so important, don't use i = work[s] because it's maybe TLE
            int v = point[i];
            if (flow[i] < cap[i] && Dist[v] == Dist[s] + 1) {
                long long D = DFS(v, t, min(f, cap[i] - flow[i]));
                if (D > 0) {
                    flow[i] += D;
                    flow[i ^ 1] -= D;
                    return D;
                }
            }
        }
        return 0;
    }

    long long maxFlow(int s, int t) { ///if flow > int, use long long
        long long Flow = 0;
        while (BFS(s, t)) {
            for (int i = 0; i <= n; i++) work[i] = head[i];
            while (true) {
                long long d = DFS(s, t, oo);
                if (d == 0) break;
                Flow += d;
            }
        }
        return Flow;
    }

    int GetFlow(int idEdge) {
        return flow[idEdge];
    }
};

pair<int, int> p[maxN];
int w[maxN];
void sol() {
    int n;
    cin >> n;
    long long sum = 0;
    for (int i = 1; i <= n; i++) {
        cin >> p[i].first >> p[i].second >> w[i];
        sum += w[i];
    }
    //even/even must be between in path
    //must have 2 parallel to the x-asis in path
    //S -> odd/odd -> even/odd -> even/even -> odd/even -> T
    //vertex u -> indeg(u) = u, outdeg(u) = u + n

    auto type = [&](int i) {
        int x = p[i].first;
        int y = p[i].second;
        x = abs(x) % 2;
        y = abs(y) % 2;
        if (x == 1 && y == 1) return 0;
        if (x == 0 && y == 1) return 1;
        if (x == 0 && y == 0) return 2;
        if (x == 1 && y == 0) return 3;
    };

    auto indeg = [&](int u) {
        return u;
    };

    auto outdeg = [&](int u) {
        return u + n;
    };

    int S = 0, T = 2 * n + 1;
    DinicFlow df(T);

    for (int i = 1; i <= n; i++) {
        if (type(i) == 3) df.add_Edge(outdeg(i), T, INF_LL);
        else {
            for (int j = 1; j <= n; j++) {
                if (abs(p[i].first - p[j].first) + abs(p[i].second - p[j].second) == 1 && type(j) - type(i) == 1) {
                    df.add_Edge(outdeg(i), indeg(j), INF_LL);
                }
            }
        }
        if (type(i) == 0) df.add_Edge(S, indeg(i), INF_LL);
        df.add_Edge(indeg(i), outdeg(i), w[i]);
    }

    long long mnCut = df.maxFlow(S, T);
    cout << sum - mnCut;
}

void solve() {
    clock_t begin = clock();
    int T;
    //cin >> T;
    T = 1;
    int TestCase = 0;
    while (T--) {
        TestCase += 1;
        //cout << "Case #" << TestCase << ": ";
        //cout << "Test " << TestCase << ": ";
        sol();
        //if (T) cout << '\n';
    }
    clock_t end = clock();
    cerr << "Time: " << fixed << setprecision(10) << (double)(end - begin) / (double)CLOCKS_PER_SEC << '\n';
}

int main(int argc,char *argv[]) {
    ///srand(Time(nullptr));
    ios_base::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);
    open_file();
    solve();
}

### Prompt

Please formulate a CPP solution to the following problem:

At the foot of Liyushan Mountain, n tents will be carefully arranged to provide accommodation for those who are willing to experience the joy of approaching nature, the tranquility of the night, and the bright starry sky.

The i-th tent is located at the point of (x_i, y_i) and has a weight of w_i. A tent is important if and only if both x_i and y_i are even. You need to remove some tents such that for each remaining important tent (x, y), there do not exist 3 other tents (x'_1, y'_1), (x'_2, y'_2) and (x'_3, y'_3) such that both conditions are true: 

  1. |x'_j-x|, |y'_j - y|≤ 1 for all j ∈ \{1, 2, 3\}, and 
  2. these four tents form a parallelogram (or a rectangle) and one of its sides is parallel to the x-axis. 



Please maximize the sum of the weights of the tents that are not removed. Print the maximum value.

Input

The first line contains a single integer n (1≤ n≤ 1 000), representing the number of tents.

Each of the next n lines contains three integers x_i, y_i and w_i (-10^9≤ x_i,y_i ≤ 10^9, 1≤ w_i≤ 10^9), representing the coordinate of the i-th tent and its weight. No two tents are located at the same point.

Output

A single integer — the maximum sum of the weights of the remaining tents.

Examples

Input


5
0 0 4
0 1 5
1 0 3
1 1 1
-1 1 2


Output


12


Input


32
2 2 1
2 3 1
3 2 1
3 3 1
2 6 1
2 5 1
3 6 1
3 5 1
2 8 1
2 9 1
1 8 1
1 9 1
2 12 1
2 11 1
1 12 1
1 11 1
6 2 1
7 2 1
6 3 1
5 3 1
6 6 1
7 6 1
5 5 1
6 5 1
6 8 1
5 8 1
6 9 1
7 9 1
6 12 1
5 12 1
6 11 1
7 11 1


Output


24

Note

Here is an illustration of the second example. Black triangles indicate the important tents. This example also indicates all 8 forbidden patterns.

<image>

### Response

```cpp
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

using namespace std;

#define INP "solve"
#define OUT "solve"

const long long INF_LL = 4e18;
const int INF = 1e9 + 100;
const int MOD = 1e9 + 7;
const int Base = 311;
const long double EPS = 1e-10;
const int BLOCK = 550;
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());

void open_file() {
    #ifdef THEMIS
        freopen(INP ".inp","r",stdin);
        freopen(OUT ".out","w",stdout);
    #endif // THEMIS
}

const int maxN = 1e5 + 100;

struct DinicFlow { ///Base 0-th, The vertices are numbered from 0 to n - 1
    const long long oo = INF_LL; ///if flow > int, use long long
    int n, numEdge;
    vector <int> point, next, head, Dist, work;
    vector <long long> flow, cap; ///if flow > int, use long long

    DinicFlow(int _n = 0) {
        n = _n; numEdge = 0;
        head.assign(n + 7, -1);
        work.assign(n + 7, -1);
        Dist.assign(n + 7, 0);
    }

    void add_Edge(int u, int v, long long c1, long long c2 = 0) {///if flow > int, use long long c1, c2
        ///u -> v: c1
        point.push_back(v); flow.push_back(0); cap.push_back(c1); next.push_back(head[u]); head[u] = numEdge++;
        ///v -> u: c2
        point.push_back(u); flow.push_back(0); cap.push_back(c2); next.push_back(head[v]); head[v] = numEdge++;
    }

    bool BFS(int s, int t) { ///check has path from s to t
        queue <int> Q;
        for (int i = 0; i <= n; i++) Dist[i] = -1;
        Dist[s] = 0;
        Q.push(s);
        while ((int)Q.size() != 0) {
            int u = Q.front(); Q.pop();
            for (int i = head[u]; i >= 0; i = next[i]) {
                int v = point[i];
                if (flow[i] < cap[i] && Dist[v] == -1) {
                    Dist[v] = Dist[u] + 1;
                    if (v == t) return true;
                    Q.push(v);
                }
            }
        }
        return false;
    }

    long long DFS(int s, int t, long long f) { ///if flow > int, use long long
        if (f == 0) ///Min F always >= 0 so if f = 0 break recursive
            return f;
        if (s == t)
            return f;
        for (int &i = work[s]; i >= 0; i = next[i]) { ///&i so important, don't use i = work[s] because it's maybe TLE
            int v = point[i];
            if (flow[i] < cap[i] && Dist[v] == Dist[s] + 1) {
                long long D = DFS(v, t, min(f, cap[i] - flow[i]));
                if (D > 0) {
                    flow[i] += D;
                    flow[i ^ 1] -= D;
                    return D;
                }
            }
        }
        return 0;
    }

    long long maxFlow(int s, int t) { ///if flow > int, use long long
        long long Flow = 0;
        while (BFS(s, t)) {
            for (int i = 0; i <= n; i++) work[i] = head[i];
            while (true) {
                long long d = DFS(s, t, oo);
                if (d == 0) break;
                Flow += d;
            }
        }
        return Flow;
    }

    int GetFlow(int idEdge) {
        return flow[idEdge];
    }
};

pair<int, int> p[maxN];
int w[maxN];
void sol() {
    int n;
    cin >> n;
    long long sum = 0;
    for (int i = 1; i <= n; i++) {
        cin >> p[i].first >> p[i].second >> w[i];
        sum += w[i];
    }
    //even/even must be between in path
    //must have 2 parallel to the x-asis in path
    //S -> odd/odd -> even/odd -> even/even -> odd/even -> T
    //vertex u -> indeg(u) = u, outdeg(u) = u + n

    auto type = [&](int i) {
        int x = p[i].first;
        int y = p[i].second;
        x = abs(x) % 2;
        y = abs(y) % 2;
        if (x == 1 && y == 1) return 0;
        if (x == 0 && y == 1) return 1;
        if (x == 0 && y == 0) return 2;
        if (x == 1 && y == 0) return 3;
    };

    auto indeg = [&](int u) {
        return u;
    };

    auto outdeg = [&](int u) {
        return u + n;
    };

    int S = 0, T = 2 * n + 1;
    DinicFlow df(T);

    for (int i = 1; i <= n; i++) {
        if (type(i) == 3) df.add_Edge(outdeg(i), T, INF_LL);
        else {
            for (int j = 1; j <= n; j++) {
                if (abs(p[i].first - p[j].first) + abs(p[i].second - p[j].second) == 1 && type(j) - type(i) == 1) {
                    df.add_Edge(outdeg(i), indeg(j), INF_LL);
                }
            }
        }
        if (type(i) == 0) df.add_Edge(S, indeg(i), INF_LL);
        df.add_Edge(indeg(i), outdeg(i), w[i]);
    }

    long long mnCut = df.maxFlow(S, T);
    cout << sum - mnCut;
}

void solve() {
    clock_t begin = clock();
    int T;
    //cin >> T;
    T = 1;
    int TestCase = 0;
    while (T--) {
        TestCase += 1;
        //cout << "Case #" << TestCase << ": ";
        //cout << "Test " << TestCase << ": ";
        sol();
        //if (T) cout << '\n';
    }
    clock_t end = clock();
    cerr << "Time: " << fixed << setprecision(10) << (double)(end - begin) / (double)CLOCKS_PER_SEC << '\n';
}

int main(int argc,char *argv[]) {
    ///srand(Time(nullptr));
    ios_base::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr);
    open_file();
    solve();
}

```