1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cmath>
using namespace std;

typedef vector <int > VI;
typedef vector < VI > VVI;
typedef long long LL;
typedef vector < LL > VLL;
typedef vector < double > VD;
typedef vector < string > VS;
typedef pair<int,int> PII;
typedef vector <PII> VPII;
typedef istringstream ISS;

#define ALL(x) x.begin(),x.end()
#define REP(i,n) for (int i=0; i<(n); ++i)
#define FOR(var,pocz,koniec) for (int var=(pocz); var<=(koniec); ++var)
#define FORD(var,pocz,koniec) for (int var=(pocz); var>=(koniec); --var)
#define FOREACH(it, X) for(__typeof((X).begin()) it = (X).begin(); it != (X).end(); ++it)
#define PB push_back
#define PF push_front
#define MP(a,b) make_pair(a,b)
#define ST first
#define ND second
#define SIZE(x) (int)x.size()

const int N = 210000;
const int OFFSET = 1000000000;
const int INF = 1001 * 1001 * 1001;
struct Point{ 
  LL x, y;
  int v;
} eksponaty[N], straznicy[N];
int n, m;
int w, h;

void wczytaj_przeskaluj_obroc(Point &p) {
  int x, y, v;
  scanf("%d %d %d", &x, &y, &v);
  //x += OFFSET; y += OFFSET;
  p.x = -((LL)y * w + (LL)x * h);
  p.y = -((LL)y * w - (LL)x * h);
  p.v = v;
}

void solve() {
  // sort wszystkiego rosnaco po x-ach, w przypadku remisu rosnaco po y-ach
  vector<pair<pair<LL,LL>, int> > v;
  v.reserve(n+m);
  REP(i,n) v.PB(MP(MP(eksponaty[i].x, eksponaty[i].y), i+1));
  REP(i,m) v.PB(MP(MP(straznicy[i].x, straznicy[i].y), -(i+1)));

  //REP(i,n) REP(j,m) if (straznicy[j].x <= eksponaty[i].x && straznicy[j].y <= eksponaty[i].y) printf("straznik v=%d widzi eksponat v=%d\n", straznicy[j].v, eksponaty[i].v);

  sort(ALL(v));
  // idziemy w porzadku i dla straznika wrzucamy go do zbioru posortowanego po y-ach
  set<pair<LL,int> > zbior; //(y, v) straznicy
  LL res = 0;
  REP(i,n) res += eksponaty[i].v;

  FOREACH(it, v) {
    if (it->ND >= 0) {
      //eksponat
      // w przypadku eksponatu kojarzymy go ze straznikiem najbardziej u gory
      int cena = eksponaty[it->ND-1].v;
      while (cena > 0) {
        set<pair<LL,int> >::iterator it2 = zbior.lower_bound(MP(it->ST.ND,INF));
        if (it2 != zbior.begin()) {
          --it2;
          int d = min(it2->ND, cena);
          pair<LL,int> np = MP(it2->ST, it2->ND - d);
          cena -= d;
          res -= d;
          zbior.erase(it2);
          if (np.ND != 0) zbior.insert(np);
        } else break;
      }
    } else {
      //straznik
      zbior.insert(MP(it->ST.ND, straznicy[-it->ND-1].v));
    }
  }
  printf("%lld\n", res);
}

int main(){
  scanf("%d %d", &n, &m);
  scanf("%d %d", &w, &h);
  REP(i,n) wczytaj_przeskaluj_obroc(eksponaty[i]);
  REP(i,m) wczytaj_przeskaluj_obroc(straznicy[i]);
  solve();
  return 0;
}