using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Debug = System.Diagnostics.Trace;
using SB = System.Text.StringBuilder;
using static System.Math;
using Number = System.Int32;

using C = System.Int32;
using V = System.Int64;
namespace Program {
	public class Solver {
		Random rnd = new Random();
		public void Solve() {
			var n = ri;
			var P = Enumerate(n, x => new KeyValuePair<int[], long>(new int[] { ri, ri }, rl));
			var m = ri;
			var Q = Enumerate(m, x => new KeyValuePair<char, int[]>(rs[0], new int[] { ri, ri }));
			var ans = 0L;

			const int X = 102;
			for (int k = 1; k <= n; k++) {
				var G = new MinCostFlow(2 * X + 2);
				var src = 2 * X;
				var sink = src + 1;

				var s = new string[] { "LR", "DU" };
				for (int p = 0; p < 2; p++) {
					var pat = s[p];
					var R = new int[X];
					var L = new int[X];
					for (int i = 0; i < X; i++) R[i] = k;
					foreach (var x in Q) {
						var u = x.Value[0];
						var v = Min(k, x.Value[1]);
						if (x.Key == pat[0]) {
							R[u] = Min(R[u], v);
						}
						else if (x.Key == pat[1]) {
							L[u - 1] = Max(L[u - 1], k - v);
						}
					}
					L[X - 1] = R[X - 1] = k;
					for (int i = 1; i < X; i++)
						L[i] = Max(L[i], L[i - 1]);
					for (int i = X - 2; i >= 0; i--)
						R[i] = Min(R[i], R[i + 1]);
					Debug.WriteLine(L.AsJoinedString());
					Debug.WriteLine(R.AsJoinedString());

					//x座標が i 以下のやつは L[i] 以上 R[i] 以下
					for (int i = 0; i < X; i++) {
						if (p == 0) {
							var cap = i == 0 ? L[i] : L[i] - L[i - 1];
							G.AddDirectedEdge(src, i, cap, 0);
							if (i > 0)
								G.AddDirectedEdge(i, i - 1, R[i - 1] - L[i - 1], 0);
						}
						else {
							var cap = i == 0 ? L[i] : L[i] - L[i - 1];
							G.AddDirectedEdge(X + i, sink, cap, 0);
							if (i > 0)
								G.AddDirectedEdge(X + i - 1, X + i, R[i - 1] - L[i - 1], 0);
						}
					}
				}
				foreach (var x in P) {
					var u = x.Key;
					var v = x.Value;
					Debug.WriteLine($"{u[0]} {u[1]} {v}");
					G.AddDirectedEdge(u[0], X + u[1], 1, -v);
				}

				var res = G.Execute(src, sink, k);
				Debug.WriteLine(res);
				if (res.Key == k) ans = Max(ans, -res.Value);
				/*
				for (int i = 0; i < X; i++)
					foreach (var e in G.G[i])
						if (e.To >= X && e.To != src && e.Cap == 0)
							Console.WriteLine($"{i} {e.To - X} {-e.Cost}");
							*/
			}
			Console.WriteLine(ans);
		}

		const long INF = 1L << 60;
		static int[] dx = { -1, 0, 1, 0 };
		static int[] dy = { 0, 1, 0, -1 };
		int ri { get { return sc.Integer(); } }
		long rl { get { return sc.Long(); } }
		double rd { get { return sc.Double(); } }
		string rs { get { return sc.Scan(); } }
		public IO.StreamScanner sc = new IO.StreamScanner(Console.OpenStandardInput());

		static T[] Enumerate<T>(int n, Func<int, T> f) {
			var a = new T[n];
			for (int i = 0; i < a.Length; ++i) a[i] = f(i);
			return a;
		}
		static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
	}
}

#region main
static class Ex {
	static public string AsString(this IEnumerable<char> ie) { return new string(ie.ToArray()); }
	static public string AsJoinedString<T>(this IEnumerable<T> ie, string st = " ") {
		return string.Join(st, ie);
	}
	static public void Main() {
		Console.SetOut(new Program.IO.Printer(Console.OpenStandardOutput()) { AutoFlush = true });
		var solver = new Program.Solver();
		//* 
		var t = new System.Threading.Thread(solver.Solve, 50000000);
		t.Start();
		t.Join();
		//*/
		// solver.Solve();
		Console.Out.Flush();
	}
}
#endregion
#region Ex
namespace Program.IO {
	using System.IO;
	using System.Text;
	using System.Globalization;

	public class Printer : StreamWriter {
		public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
		public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
	}

	public class StreamScanner {
		public StreamScanner(Stream stream) { str = stream; }

		public readonly Stream str;
		private readonly byte[] buf = new byte[1024];
		private int len, ptr;
		public bool isEof = false;
		public bool IsEndOfStream { get { return isEof; } }

		private byte read() {
			if (isEof) return 0;
			if (ptr >= len) {
				ptr = 0;
				if ((len = str.Read(buf, 0, 1024)) <= 0) {
					isEof = true;
					return 0;
				}
			}
			return buf[ptr++];
		}

		public char Char() {
			byte b = 0;
			do b = read(); while ((b < 33 || 126 < b) && !isEof);
			return (char)b;
		}
		public string Scan() {
			var sb = new StringBuilder();
			for (var b = Char(); b >= 33 && b <= 126; b = (char)read()) sb.Append(b);
			return sb.ToString();
		}
		public string ScanLine() {
			var sb = new StringBuilder();
			for (var b = Char(); b != '\n' && b != 0; b = (char)read()) if (b != '\r') sb.Append(b);
			return sb.ToString();
		}
		public long Long() { return isEof ? long.MinValue : long.Parse(Scan()); }
		public int Integer() { return isEof ? int.MinValue : int.Parse(Scan()); }
		public double Double() { return isEof ? double.NaN : double.Parse(Scan(), CultureInfo.InvariantCulture); }
	}
}

#endregion

#region Set
/// <summary>
/// 要素の追加、削除、検索、取得が可能な集合を表します．
/// </summary>
/// <typeparam name="T">優先度付きキュー内の要素の型を指定します．</typeparam>
/// <remarks>内部的にはAVL木によって実装されています．</remarks>
public class Set<T> {
	Node root;
	readonly IComparer<T> comparer;
	readonly Node nil;
	/// <summary>
	/// 多重集合かどうかを表します．
	/// </summary>
	public bool IsMultiSet { get; set; }
	public Set(IComparer<T> comparer) {
		nil = new Node(default(T));
		root = nil;
		this.comparer = comparer;
	}
	public Set(Comparison<T> comaprison) : this(Comparer<T>.Create(comaprison)) { }
	public Set() : this(Comparer<T>.Default) { }
	/// <summary>
	/// 要素をコレクションに追加します．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public bool Add(T v) {
		return insert(ref root, v);
	}
	/// <summary>
	/// v が存在するならコレクションから削除します．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public bool Remove(T v) {
		return remove(ref root, v);
	}
	/// <summary>
	/// 0-indexed で index 番目の要素をコレクションから取得します．．
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public T this[int index] { get { return find(root, index); } }
	public int Count { get { return root.Count; } }
	public void RemoveAt(int k) {
		if (k < 0 || k >= root.Count) throw new ArgumentOutOfRangeException();
		removeAt(ref root, k);
	}
	/// <summary>
	/// このコレクションに含まれる要素を昇順に並べて返します．
	/// </summary>
	/// <remarks>この操作は計算量 O(N) で実行されます．</remarks>
	public T[] Items {
		get {
			var ret = new T[root.Count];
			var k = 0;
			walk(root, ret, ref k);
			return ret;
		}
	}
	void walk(Node t, T[] a, ref int k) {
		if (t.Count == 0) return;
		walk(t.lst, a, ref k);
		a[k++] = t.Key;
		walk(t.rst, a, ref k);
	}

	bool insert(ref Node t, T key) {
		if (t.Count == 0) { t = new Node(key); t.lst = t.rst = nil; t.Update(); return true; }
		var cmp = comparer.Compare(t.Key, key);
		bool res;
		if (cmp > 0)
			res = insert(ref t.lst, key);
		else if (cmp == 0) {
			if (IsMultiSet) res = insert(ref t.lst, key);
			else return false;
		}
		else res = insert(ref t.rst, key);
		balance(ref t);
		return res;
	}
	bool remove(ref Node t, T key) {
		if (t.Count == 0) return false;
		var cmp = comparer.Compare(key, t.Key);
		bool ret;
		if (cmp < 0) ret = remove(ref t.lst, key);
		else if (cmp > 0) ret = remove(ref t.rst, key);
		else {
			ret = true;
			var k = t.lst.Count;
			if (k == 0) { t = t.rst; return true; }
			if (t.rst.Count == 0) { t = t.lst; return true; }


			t.Key = find(t.lst, k - 1);
			removeAt(ref t.lst, k - 1);
		}
		balance(ref t);
		return ret;
	}
	void removeAt(ref Node t, int k) {
		var cnt = t.lst.Count;
		if (cnt < k) removeAt(ref t.rst, k - cnt - 1);
		else if (cnt > k) removeAt(ref t.lst, k);
		else {
			if (cnt == 0) { t = t.rst; return; }
			if (t.rst.Count == 0) { t = t.lst; return; }

			t.Key = find(t.lst, k - 1);
			removeAt(ref t.lst, k - 1);
		}
		balance(ref t);
	}
	void balance(ref Node t) {
		var balance = t.lst.Height - t.rst.Height;
		if (balance == -2) {
			if (t.rst.lst.Height - t.rst.rst.Height > 0) { rotR(ref t.rst); }
			rotL(ref t);
		}
		else if (balance == 2) {
			if (t.lst.lst.Height - t.lst.rst.Height < 0) rotL(ref t.lst);
			rotR(ref t);
		}
		else t.Update();
	}

	T find(Node t, int k) {
		if (k < 0 || k > root.Count) throw new ArgumentOutOfRangeException();
		for (; ; )
		{
			if (k == t.lst.Count) return t.Key;
			else if (k < t.lst.Count) t = t.lst;
			else { k -= t.lst.Count + 1; t = t.rst; }
		}
	}
	/// <summary>
	/// コレクションに含まれる要素であって、 v 以上の最小の要素の番号を返します。
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public int LowerBound(T v) {
		var k = 0;
		var t = root;
		for (; ; )
		{
			if (t.Count == 0) return k;
			if (comparer.Compare(v, t.Key) <= 0) t = t.lst;
			else { k += t.lst.Count + 1; t = t.rst; }
		}
	}
	/// <summary>
	/// コレクションに含まれる要素であって、 v より真に大きい、最小の要素の番号を返します。
	/// </summary>
	/// <remarks>この操作は計算量 O(log N) で実行されます．</remarks>
	public int UpperBound(T v) {
		var k = 0;
		var t = root;
		for (; ; )
		{
			if (t.Count == 0) return k;
			if (comparer.Compare(t.Key, v) <= 0) { k += t.lst.Count + 1; t = t.rst; }
			else t = t.lst;
		}
	}

	void rotR(ref Node t) {
		var l = t.lst;
		t.lst = l.rst;
		l.rst = t;
		t.Update();
		l.Update();
		t = l;
	}
	void rotL(ref Node t) {
		var r = t.rst;
		t.rst = r.lst;
		r.lst = t;
		t.Update();
		r.Update();
		t = r;
	}


	class Node {
		public Node(T key) {
			Key = key;
		}
		public int Count { get; private set; }
		public sbyte Height { get; private set; }
		public T Key { get; set; }
		public Node lst, rst;
		public void Update() {
			Count = 1 + lst.Count + rst.Count;
			Height = (sbyte)(1 + Math.Max(lst.Height, rst.Height));
		}
		public override string ToString() {
			return string.Format("Count = {0}, Key = {1}", Count, Key);
		}
	}
}
#endregion

#region Mincost Flow
/// <summary>
/// 辺の追加を行い，最小費用流を求めることが可能なグラフです．
/// </summary>
public class MinCostFlow {
	bool hasng;
	public readonly List<Edge>[] G;
	/// <summary>
	/// 頂点数 <paramref name="V"/> で辺が存在しないグラフを構築します．
	/// </summary>
	/// <param name="V">頂点の数</param>
	/// <remarks>この操作は O(<paramref name="V"/>) で実行されます．</remarks>
	public MinCostFlow(int V) {
		G = new List<Edge>[V];
		for (int i = 0; i < V; i++)
			G[i] = new List<Edge>();

	}
	/// <summary>
	/// 頂点 <paramref name="from"/> から頂点 <paramref name="to"/> への容量 <paramref name="cap"/> ，コスト <paramref name="cost"/> の有向辺を追加します．
	/// </summary>
	/// <param name="from">始点となる頂点の 0-indexed での番号</param>
	/// <param name="to">終点となる頂点の 0-indexed での番号</param>
	/// <param name="cap">辺の容量</param>
	/// <param name="cost">辺のコスト</param>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public void AddDirectedEdge(int from, int to, C cap, V cost) {
		addEdge(from, to, cap, 0, cost);
	}

	/// <summary>
	/// 頂点 <paramref name="src"/> から頂点 <paramref name="sink"/> へ最大で流量 <paramref name="f"/> だけ最小費用フローを流します．
	/// </summary>
	/// <param name="src">ソースとなる頂点の 0-indexed での番号</param>
	/// <param name="sink">シンクとなる頂点の 0-indexed での番号</param>
	/// <param name="f">ソースからシンクへと流す最大の容量．-1を指定した場合，最小費用最大流を求める．</param>
	/// <param name="inf">ソースからシンクまでの距離の最大値</param>
	/// <remarks>この操作はPrimal Dual法に基づき，最悪計算量 O(VE + FE log V) で実行されます．Vは頂点の数，Eは辺の数，Fは流量を表します．</remarks>
	public KeyValuePair<C, V> Execute(int src, int sink, C f = C.MaxValue, V inf = V.MaxValue / 3) {
		var n = G.Length;
		var dist = new V[n];
		var prev = new int[n];
		var prevEdge = new Edge[n];
		var potential = new V[n];


		C flow = 0;
		V cost = 0;
		var first = hasng;
		while (f > 0) {
			for (int i = 0; i < G.Length; i++)
				dist[i] = inf;

			//shortest path
			if (first)//spfa
			{
				var q = new Queue<int>();
				q.Enqueue(src); dist[src] = 0;
				var inQ = new bool[n];
				while (q.Count > 0) {
					var p = q.Dequeue();
					inQ[p] = false;
					foreach (var e in G[p]) {
						var t = e.To;
						var d = dist[p] + e.Cost;
						if (e.Cap > 0 && d < dist[t]) {
							if (!inQ[t]) {
								inQ[t] = true;
								q.Enqueue(t);
							}
							dist[t] = d; prev[t] = p; prevEdge[t] = e;
						}
					}
				}
				first = false;
			}
			else//dijkstra
			{
				var vis = new bool[n];
				var pq = new PriorityQueue<KeyValuePair<int, V>>((l, r) => l.Value.CompareTo(r.Value));
				pq.Enqueue(new KeyValuePair<int, V>(src, 0));
				dist[src] = 0;
				while (pq.Count > 0) {
					var p = pq.Dequeue().Key;
					if (vis[p]) continue;
					vis[p] = true;
					foreach (var e in G[p]) {
						if (e.Cap <= 0) continue;
						var t = e.To;
						if (vis[t]) continue;
						var d = dist[p] + e.Cost + potential[p] - potential[t];
						if (dist[t] > d) {
							dist[t] = d; prev[t] = p; prevEdge[t] = e;
							pq.Enqueue(new KeyValuePair<int, V>(t, d));
						}
					}
				}


			}


			//update
			{
				if (dist[sink] == inf) break;
				for (int i = 0; i < n; i++)
					potential[i] = Math.Min(inf, potential[i] + dist[i]);
				C df = f;
				V d = 0;
				for (var v = sink; v != src; v = prev[v]) {
					var e = prevEdge[v];
					df = Math.Min(df, e.Cap); d += e.Cost;
				}
				f -= df; cost += df * d; flow += df;
				for (var v = sink; v != src; v = prev[v]) {
					var e = prevEdge[v];
					e.Cap -= df; e.Rev.Cap += df;
				}
			}

		}
		return new KeyValuePair<C, V>(flow, cost);
	}
	void addEdge(int f, int t, C c1, C c2, V e) {
		if (e < 0) hasng = true;
		var a = new Edge(t, c1, e);
		var b = new Edge(f, c2, -e);
		Edge.Link(a, b);
		G[f].Add(a);
		G[t].Add(b);
	}
	public class Edge {
		public static void Link(Edge e1, Edge e2) {
			e1.Rev = e2; e2.Rev = e1;
		}
		public int To { get; private set; }
		public Edge Rev { get; private set; }
		public V Cost { get; private set; }
		public C Cap { get; set; }
		public Edge(int t, C c, V e) {
			To = t;
			Cap = c;
			Cost = e;
		}
		public override string ToString() {
			return string.Format("to: {0}, cap: {1}", To, Cap);
		}
	}
}
#endregion
#region PriorityQueue
/// <summary>
/// 指定した型のインスタンスを最も価値が低い順に取り出すことが可能な可変サイズのコレクションを表します．
/// </summary>
/// <typeparam name="T">優先度付きキュー内の要素の型を指定します．</typeparam>
/// <remarks>内部的にはバイナリヒープによって実装されています．</remarks>
public class PriorityQueue<T> {
	readonly List<T> heap = new List<T>();
	readonly Comparison<T> cmp;

	/// <summary>
	/// デフォルトの比較子を使用してインスタンスを初期化します．
	/// </summary>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public PriorityQueue() { cmp = Comparer<T>.Default.Compare; }

	/// <summary>
	/// デリゲートで表されるような比較関数を使用してインスタンスを初期化します．
	/// </summary>
	/// <param name="comparison"></param>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public PriorityQueue(Comparison<T> comparison) { cmp = comparison; }

	/// <summary>
	/// 指定された比較子を使用してインスタンスを初期化します．
	/// </summary>
	/// <param name="comparer"></param>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public PriorityQueue(IComparer<T> comparer) { cmp = comparer.Compare; }

	/// <summary>
	/// 優先度付きキューに要素を追加します．
	/// </summary>
	/// <param name="item">優先度付きキューに追加される要素</param>
	/// <remarks>最悪計算量 O(log N) で実行されます．</remarks>
	public void Enqueue(T item) {
		var pos = heap.Count;
		heap.Add(item);
		while (pos > 0) {
			var par = (pos - 1) / 2;
			if (cmp(heap[par], item) <= 0)
				break;
			heap[pos] = heap[par];
			pos = par;
		}
		heap[pos] = item;

	}

	/// <summary>
	/// 優先度付きキューから最も価値が低い要素を削除し，返します．
	/// </summary>
	/// <returns>優先度付きキューから削除された要素．</returns>
	/// <remarks>最悪計算量 O(log N) で実行されます．</remarks>
	public T Dequeue() {
		var ret = heap[0];
		var pos = 0;
		var x = heap[heap.Count - 1];

		while (pos * 2 + 1 < heap.Count - 1) {
			var lch = pos * 2 + 1;
			var rch = pos * 2 + 2;
			if (rch < heap.Count - 1 && cmp(heap[rch], heap[lch]) < 0) lch = rch;
			if (cmp(heap[lch], x) >= 0)
				break;
			heap[pos] = heap[lch];
			pos = lch;
		}
		heap[pos] = x;
		heap.RemoveAt(heap.Count - 1);
		return ret;

	}
	/// <summary>
	///  優先度付きキューに含まれる最も価値が低い要素を削除せずに返します．
	/// </summary>
	/// <returns>優先度付きキューに含まれる最も価値が低い要素．</returns>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public T Peek() { return heap[0]; }

	/// <summary>
	/// 優先度付きキュー内の要素の数を取得します．
	/// </summary>
	/// <returns>優先度付キュー内にある要素の数</returns>
	/// <remarks>最悪計算量 O(1) で実行されます．</remarks>
	public int Count { get { return heap.Count; } }
	/// <summary>
	/// 優先度付きキュー内に要素が存在するかどうかを O(1) で判定します．
	/// </summary>
	/// <returns>優先度付キュー内にある要素が存在するならば true，そうでなければ　false．</returns>
	/// <remarks>この操作は O(1) で実行されます．</remarks>
	public bool Any() { return heap.Count > 0; }

	/// <summary>
	/// 優先度付きキューに含まれる要素を昇順に並べて返します．
	/// </summary>
	/// <remarks>この操作は計算量 O(N log N) で実行されます．</remarks>
	public T[] Items {
		get {
			var ret = heap.ToArray();
			Array.Sort(ret, cmp);
			return ret;
		}
	}
}
#endregion


Measured memory_bytes: 19920