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.*;
import java.util.*;

public class tr0 {
	static PrintWriter out;
	static StringBuilder sb;
	static int inf =(int) 1e7;
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		out = new PrintWriter(System.out);
		segmentTree []a=new segmentTree[26];
		int n=sc.nextInt();
		int q=sc.nextInt();
		for(int i=0;i<26;i++) {
			int []o=new int[n+1];
			a[i]=new segmentTree(o);
		}
		char []c=sc.nextLine().toCharArray();
		for(int i=0;i<n;i++) {
			a[c[i]-'a'].updateRange(i+1, i+1, 1);    
		}
		//out.println(Arrays.toString(a));
		for(int i=0;i<q;i++) {
			int l=sc.nextInt(); int r=sc.nextInt();
			if(sc.nextInt()==1) {
				int last=l;
				for(int j=0;j<26;j++) {
					int y=a[j].query(l, r);
					//out.println(y+" "+((char)('a'+j)));
					a[j].updateRange(l, r, 0);
					//if(j==1)
					//	out.print(a[j]);
					if(y!=0) {
					a[j].updateRange(last, last+y-1, 1);
					if(last+y>r)
						break;
					}
					last+=y;
				//	out.println(a[j]);
				}
			}
			else {
				int last=l;
				for(int j=25;j>=0;j--) {
					int y=a[j].query(l, r);
			//		out.println(y+" "+((char)('a'+j)));
					if(y!=0) {
						a[j].updateRange(l, r, 0);
					a[j].updateRange(last, last+y-1, 1);
					if(last+y>r)
					break;
					}
					last+=y;
				}
			}
		}
		//out.println(Arrays.toString(a)+"J");
		char []ans=new char[n+1];
		for(int i=1;i<n+1;i++) {
			for(int o=0;o<26;o++)
				if(a[o].query(i, i)==1) {
					ans[i]=(char)('a'+o);
					break;
				}
		}
	//	out.println(Arrays.toString(a));
		//out.println(Arrays.toString(ans));
		for(int i=1;i<n+1;i++)
			out.print(ans[i]);
		out.flush();
	}
	static public class segmentTree{
		int [] array,tree,lazy;
		int n;
		segmentTree(int []aa){
			array=aa;
			n=array.length-1;
			tree=new int [n*4];
			lazy=new int[n*4];
			Arrays.fill(lazy, -1);
			build(1,1,n);
		}
		public String toString() {
			return Arrays.toString(tree);
		}
		void build(int node,int l,int r) {
			if(l==r)
				tree[node]=array[r];
			else {
				int mid=(l+r)>>1;
				build(node<<1,l,mid);
				build((node<<1)|1,mid+1,r);
				tree[node]=tree[node<<1]+tree[node<<1|1];
			}
		}
		void updateRange(int i,int j,int v) {
			updateR(1,1,n,i,j,v);
		}
		void updateR(int node,int l,int r,int i,int j,int v) {
			if(i>r || j<l)
				return;
			if(i<= l && j>=r) {
				tree[node] = (r-l+1)*v;			
				lazy[node] = v;
			}
			else {
				int mid=l+r>>1;
			propagate(node, l, mid, r);
			updateR(node<<1,l,mid,i,j,v);
			updateR(node<<1|1,mid+1,r,i,j,v);
			tree[node] = tree[node<<1] + tree[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];
			tree[node<<1] = (mid-b+1)*lazy[node];		
			tree[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 tree[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 long mod=(long) 1e9+7;
     static long fac (int n) {
    	 if(n==0)
    		 return 1;
    	 if(n==1)
    		 return 1;
    	 long ans=1;
    	 for(int i=1;i<=n;i++)
    		 ans=(i%mod*ans%mod)%mod;
    	 return ans%mod;
     }
    	 static int gcd(int a, int b) {
     
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}
    static class pair implements Comparable<pair>{
    	int num;
    	int v;
    	pair(int n,int v){
    		num=n;
    		this.v=v;
    	}
    	public String toString() {
    		return num+" "+v;
    	}
	
		public int compareTo(pair o) {
			return o.v-v;
		}
    }
	static class unionfind {
		int[] p;
		int[] size;

		unionfind(int n) {
			p = new int[n];
			size = new int[n];

			for (int i = 0; i < n; i++) {
				p[i] = i;
			}
			Arrays.fill(size, 1);
		}

		int findSet(int v) {
			if (v == p[v])
				return v;
			return p[v] = findSet(p[v]);
		}

		boolean sameSet(int a, int b) {
			a = findSet(a);
			b = findSet(b);
			if (a == b)
				return true;
			return false;
		}

		int max() {
			int max = 0;
			for (int i = 0; i < size.length; i++)
				if (size[i] > max)
					max = size[i];
			return max;
		}

		void combine(int a, int b) {
			a = findSet(a);
			b = findSet(b);
			if (a == b)
				return;
			if (size[a] > size[b]) {
				p[b] = a;
				size[a] += size[b];

			} else {
				p[a] = b;
				size[b] += size[a];
			}
		}
	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

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

		public Scanner(String file) throws Exception {
			br = new BufferedReader(new FileReader(file));
		}

		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() throws InterruptedException {
			Thread.sleep(3000);
		}
	}
}