Problem: This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k = 1 or in non-increasing order if k = 0.

Output the final string after applying the queries.

Input

The first line will contain two integers n, q (1 ≤ n ≤ 105, 0 ≤ q ≤ 50 000), the length of the string and the number of queries respectively. 

Next line contains a string S itself. It contains only lowercase English letters.

Next q lines will contain three integers each i, j, k (1 ≤ i ≤ j ≤ n, <image>).

Output

Output one line, the string S after applying the queries.

Examples

Input

10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1


Output

cbcaaaabdd

Input

10 1
agjucbvdfk
1 10 1


Output

abcdfgjkuv

Note

First sample test explanation:

<image>

<image>

<image>

<image>

<image>

Solution (in JAVA):

Solution:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class ASimpleTask {

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out);

		int n = sc.nextInt();
		int q = sc.nextInt();
		String s = sc.nextLine();
		
		SegmentTree[] trees = new SegmentTree[26];
		
		int N = 1; while(N < n) N <<= 1;
		
		for (int i = 0; i < 26; i++) {
			int[] in = new int[N + 1];
			for (int j = 0; j < n; j++) {
				if(s.charAt(j) == 'a' + i)
					in[j + 1] = 1;
			}
			trees[i] = new SegmentTree(in);
		}
		
		for (int i = 0; i < q; i++) {
			int l = sc.nextInt();
			int r = sc.nextInt();
			int k = sc.nextInt();
			
			
			if( k == 1){
				int start = l;
				for (int j = 0; j < 26; j++) {
					int a = trees[j].query(l, r);
					trees[j].update_range(l, r, 0);
					trees[j].update_range(start, start + a - 1, 1);
					start += a;
				}
			}else{
				int start = r;
				for (int j = 0; j < 26; j++) {
					int a = trees[j].query(l, r);
					trees[j].update_range(l, r, 0);
					trees[j].update_range(start - a + 1, start, 1);
					start -= a;
				}
			}
			
		}
		
		char[] ans = new char[n];
		for (int i = 0; i < n; i++) {
			ans[i] = '?';
		}
		
		for (int i = 0; i < 26; i++) {
			for (int j = 1; j <= n; j++) {
				if(trees[i].query(j, j) == 1)
					ans[j - 1] = (char) ('a' + i);
			}
		}
		
		for (int i = 0; i < n; i++) {
			out.print(ans[i]);
		}
		out.println();
		out.flush();
		out.close();

	}

	static public class SegmentTree {		// 1-based DS, OOP

		int N; 			//the number of elements in the array as a power of 2 (i.e. after padding)
		int[] array, sTree, lazy;

		SegmentTree(int[] in)		
		{
			array = in; N = in.length - 1;
			sTree = new int[N<<1];		//no. of nodes = 2*N - 1, we add one to cross out index zero
			lazy = new int[N<<1];
			Arrays.fill(lazy, -1);
			build(1,1,N);
		}

		void build(int node, int b, int e)	// O(n)
		{
			if(b == e)					
				sTree[node] = array[b];
			else						
			{
				int mid = b + e >> 1;
			build(node<<1,b,mid);
			build(node<<1|1,mid+1,e);
			sTree[node] = sTree[node<<1]+sTree[node<<1|1];
			}
		}


		void update_range(int i, int j, int val)		// O(log n) 
		{
			update_range(1,1,N,i,j,val);
		}

		void update_range(int node, int b, int e, int i, int j, int val)
		{
			if(i > e || j < b)		
				return;
			if(b >= i && e <= j)		
			{
				sTree[node] = (e-b+1)*val;			
				lazy[node] = val;				
			}							
			else		
			{
				int mid = b + e >> 1;
			propagate(node, b, mid, e);
			update_range(node<<1,b,mid,i,j,val);
			update_range(node<<1|1,mid+1,e,i,j,val);
			sTree[node] = sTree[node<<1] + sTree[node<<1|1];		
			}

		}
		void propagate(int node, int b, int mid, int e)		
		{
			if(lazy[node] != -1){
				lazy[node<<1] = lazy[node];
				lazy[node<<1|1] = lazy[node];
				sTree[node<<1] = (mid-b+1)*lazy[node];		
				sTree[node<<1|1] = (e-mid)*lazy[node];		
				lazy[node] = -1;
			}
		}

		int query(int i, int j)
		{
			return query(1,1,N,i,j);
		}

		int query(int node, int b, int e, int i, int j)	// O(log n)
		{
			if(i>e || j <b)
				return 0;		
			if(b>= i && e <= j)
				return sTree[node];
			int mid = b + e >> 1;
			propagate(node, b, mid, e);
			int q1 = query(node<<1,b,mid,i,j);
			int q2 = query(node<<1|1,mid+1,e,i,j);
			return q1 + q2;	

		}
	}

	static class Scanner 



	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s){	br = new BufferedReader(new InputStreamReader(s));}

		public String next() throws IOException 
		{
			while (st == null || !st.hasMoreTokens()) 
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {return Integer.parseInt(next());}

		public long nextLong() throws IOException {return Long.parseLong(next());}

		public String nextLine() throws IOException {return br.readLine();}


		public double nextDouble() throws IOException
		{
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if(x.charAt(0) == '-')
			{
				neg = true;
				start++;
			}
			for(int i = start; i < x.length(); i++)
				if(x.charAt(i) == '.')
				{
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				}
				else
				{
					sb.append(x.charAt(i));
					if(dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg?-1:1);
		}

		public boolean ready() throws IOException {return br.ready();}



	}

}