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 D {

	
	public static void main(String[] args) throws IOException
	{	
		Scanner sc = new Scanner(System.in);
		PrintWriter out = new PrintWriter(System.out); 
		int n = sc.nextInt(), q = sc.nextInt();
		int[] a = new int[n];
		String s = sc.next();
		for(int i = 0; i < n; i++)
			a[i] = s.charAt(i) - 'a';
		
		int N = 1; while(N < n) N<<=1;
		SegmentTree9[] sTrees = new SegmentTree9[27];
		for(int i = 0; i < 27; i++)
		{
			int[] in = new int[N+1];
			for(int j = 1; j <= n; j++)
				if(a[j-1] == i)
					in[j] = 1;
			sTrees[i] = new SegmentTree9(in);
		}
		while(q --> 0)
		{
			int l = sc.nextInt(), r = sc.nextInt(), type = sc.nextInt();
			int[] count = new int[27];
			for(int i = 0; i < 27; i++)
				count[i] = sTrees[i].query(l, r);
			if(type == 1)
			{
				int start = l;
				for(int i = 0; i < 27; i++)
					if(count[i] > 0)
					{
						sTrees[i].update_range(start, start + count[i] - 1, 1);
						sTrees[i].update_range(start + count[i], r, 0);
						sTrees[i].update_range(l, start-1, 0);
						start += count[i];
					}
			}
			else 
			{
				int end = r;
				for(int i = 0; i < 27; i++)
					if(count[i] > 0)
					{
						sTrees[i].update_range(end - count[i] + 1, end, 1);
						sTrees[i].update_range(l, end - count[i], 0);
						sTrees[i].update_range(end+1, r, 0);
						end -= count[i];
					}
			}
		}
		for(int i = 0; i < 27; i++)
			for(int j = 1; j <= n; j++)
				if(sTrees[i].query(j, j) == 1)
					a[j-1] = i;
		
		for(int i = 0; i < n; i++)
			out.print((char)(a[i] + 'a'));
		out.flush();
	}
	
	static class Scanner 
	{
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream System){	br = new BufferedReader(new InputStreamReader(System));	}
		public String next() throws IOException 
		{
			while (st == null || !st.hasMoreTokens()) 
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}
		public String nextLine()throws IOException{return br.readLine();}
		public int nextInt() throws IOException {return Integer.parseInt(next());}
		public double nextDouble() throws IOException {return Double.parseDouble(next());}
		public char nextChar()throws IOException{return next().charAt(0);}
		public Long nextLong()throws IOException{return Long.parseLong(next());}
		public boolean ready() throws IOException{return br.ready();}
		public void waitForInput(){for(long i = 0; i < 3e9; i++);}
	}
}

 class SegmentTree9 {
	
	int N; 			
	int[] array, sTree, lazy;
	
	SegmentTree9(int[] in)		
	{
		array = in; N = in.length - 1;
		sTree = new int[N<<1];		
		lazy = new int[N<<1];
		build(1,1,N);
		Arrays.fill(lazy, -1);
	}
	
	void build(int node, int b, int e)	// O(n)
	{
		if(b == e)					
			sTree[node] = array[b];
		else						
		{
			build(node<<1,b,(b+e)/2);
			build((node<<1)+1,(b+e)/2+1,e);
			sTree[node] = sTree[node<<1]+sTree[(node<<1)+1];
		}
	}
	
	
	void update_point(int index, int val)			// O(log n)
	{
		index += N - 1;				
		sTree[index] = val;			
		while(index>1)				
		{
			index >>= 1;
			sTree[index] = sTree[index<<1] + sTree[(index<<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		
		{
			propagate(node, b, e);
			update_range(node<<1,b,(b+e)/2,i,j,val);
			update_range((node<<1)+1,(b+e)/2+1,e,i,j,val);
			sTree[node] = sTree[node<<1] + sTree[(node<<1)+1];		
		}
		
	}
	void propagate(int node, int b, int e)		
	{
		if(lazy[node] != -1)
		{
			int mid = (b+e)/2;
			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];
		propagate(node, b, e);
		int q1 = query(node<<1,b,(b+e)/2,i,j);
		int q2 = query((node<<1)+1,(b+e)/2+1,e,i,j);
		return q1 + q2;	
				
	}
}