#include "bits/stdc++.h"

#pragma warning(disable:4996)
using namespace std;

typedef int Value1;
typedef int Value2;
const Value1 Zero1(10000000);
const Value2 Zero2(0);

struct Node {
	Value1 sum;//更新された値. この値を参照する時は評価が完全に完了しているようにする.
	Value2 lazy;	//遅延されている値を保存している
	Node() :sum(Zero1) {
		lazy = Zero2;
	}
};
struct lazy_segtree {
	int N;
	vector<Node>dat;
	lazy_segtree(int n) :N(1) {
		while (N < n) N *= 2;
		dat.resize(2 * N);
		for (int i = N - 1; i >= 1; --i) {
			update_node(i);
		}
	}

	Value2 lazy_connect(const Value2 l, const Value2 r) {
		return l+r;
	}

	void lazy_func(const int k, const int a, const int b) {
		dat[k].sum+=dat[k].lazy;
	}

	Value1 connect(const Value1 l, const Value1 r) {
		return min(l,r);

	}

	// inlineつけないと大変なことになるよ!(遅い)
	inline void lazy_evaluate_node(int k, int a, int b) {
		lazy_func(k, a, b);
		if (k < N) { // 2*k(左の子番号) < 2*N (節点の数) のイメージで. 末端ノードじゃなきゃ伝搬するのと等価.
			dat[2 * k].lazy = lazy_connect(dat[2 * k].lazy, dat[k].lazy);	//次は君が伝搬してね☆って感じ.
			dat[2 * k + 1].lazy = lazy_connect(dat[2 * k + 1].lazy, dat[k].lazy);
		}
		dat[k].lazy = Zero2;
	}

	inline void update_node(int k) { // kの子が既に評価されていることが前提. 末端以外のときしか呼び出さないような位置に書くのでif文要らない.
		dat[k].sum = connect(dat[2 * k].sum, dat[2 * k + 1].sum);

	}

	// update(l,r,v) := [l,r)を更新する. 区間は0-indexed.
	void update(int l, int r, Value2 v, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;
		if (l < 0 || r < 0)assert(false);
		lazy_evaluate_node(k, a, b); 	// とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return;
		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			dat[k].lazy = lazy_connect(dat[k].lazy, v);
			lazy_evaluate_node(k, a, b); //一回遅延評価しとかないと都合悪いので.
			return;
		}

		int m = (a + b) / 2;
		update(l, r, v, 2 * k, a, m);
		update(l, r, v, 2 * k + 1, m, b);
		update_node(k);
	}
	//get(l,r) := [l,r)に対するクエリの答えを得る. 区間は0-indexed.
	Value1 get(int l, int r, int k = 1, int a = 0, int b = -1) {
		if (b == -1)b = N;

		if (l < 0 || r<0)assert(false);
		lazy_evaluate_node(k, a, b); // とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

		if (b <= l || r <= a) //[a,b)と[l,r)が交差している場合
			return Zero1;

		if (l <= a && b <= r) { // [l,r)が[a,b)を完全に含んでいる場合
			return dat[k].sum;
		}

		int m = (a + b) / 2;
		Value1 vl = get(l, r, 2 * k, a, m);
		Value1 vr = get(l, r, 2 * k + 1, m, b);
		update_node(k);
		return connect(vl, vr);
	}
};
int main() {
	int N,M;cin>>N>>M;
	vector<pair<int,int>>sweets(N);
	for (int i = 0; i < N; ++i) {
		int a,b;cin>>a>>b;
		sweets[i]=make_pair(b,a);
	}
	sort(sweets.begin(),sweets.end(),greater<pair<int,int>>());
	vector<pair<int,int>>friends(M);
	for (int i = 0; i < M; ++i) {
		int a,b;cin>>a>>b;
		friends[i]=make_pair(a,b);
	}
	sort(friends.begin(),friends.end());
	lazy_segtree seg(friends.size());
	for (int i = 0; i < friends.size(); ++i) {
		seg.update(i,i+1,-Zero1+friends[i].second);
	}
	long long int answer=0;
	for (auto sweet : sweets) {
		int value=sweet.first;
		int price=sweet.second;
		auto it=lower_bound(friends.begin(),friends.end(),make_pair(price,int(2e9)));
		seg.update(0,it-friends.begin(),-1);
		int num=seg.get(0,friends.size());
		if (num>=1) {
			answer+=value;
		}
		else {
			seg.update(0, it - friends.begin(), 1);
		}
	}
	cout<<answer<<endl;
	return 0;
}



Measured memory_bytes: 6532