We'll call an array of n non-negative integers a[1], a[2], ..., a[n] interesting, if it meets m constraints. The i-th of the m constraints consists of three integers li, ri, qi (1 ≤ li ≤ ri ≤ n) meaning that value <image> should be equal to qi. 

Your task is to find any interesting array of n elements or state that such array doesn't exist.

Expression x&y means the bitwise AND of numbers x and y. In programming languages C++, Java and Python this operation is represented as "&", in Pascal — as "and".

Input

The first line contains two integers n, m (1 ≤ n ≤ 105, 1 ≤ m ≤ 105) — the number of elements in the array and the number of limits.

Each of the next m lines contains three integers li, ri, qi (1 ≤ li ≤ ri ≤ n, 0 ≤ qi < 230) describing the i-th limit.

Output

If the interesting array exists, in the first line print "YES" (without the quotes) and in the second line print n integers a[1], a[2], ..., a[n] (0 ≤ a[i] < 230) decribing the interesting array. If there are multiple answers, print any of them.

If the interesting array doesn't exist, print "NO" (without the quotes) in the single line.

Examples

Input

3 1
1 3 3


Output

YES
3 3 3


Input

3 2
1 3 3
1 3 2


Output

NO
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
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 CF_275D {
    
    public static class RangeTree {

        int N;
        long[] tree;
        long[] lazy; // Stores the values to be pushed-down the tree only when needed
        
        /*
         * Identities of binary operations f(IDENTITY,x)=x,
         * 0 for sum, +INF for min, -INF for max, 0 for gcd, 0 for OR, +INF for AND
         */
        long[] IDENTITY = {0,Long.MAX_VALUE}; 

        // Associative binary operation used in the tree
        private long operation(long first, long sec, int type) {
            switch (type) {
            //  The case 0 has to be used for the type of operation of the queries
                //case 0: return first + sec; // Addition
                case 0: return first |= sec; // OR
                case 1: return first &= sec; // AND
                //case 0: return Math.max(first,sec); // Maximum
                // Add cases as needed
                default: return sec; // -1 -> Assignment
            }
        }
        
        // Accumulate the operation zero (0) to be done to the sub-tree without actually pushing it down
        private long integrate(long act, long val, int nodeFrom, int nodeTo, int type) {            
            switch (type) {
                //case 0: return act + val*(nodeTo-nodeFrom+1); // Addition
                case 0: return act |= val; // OR
                case 1: return act &= val; // AND
                default: return val; // -1 -> Assignment
            }
        }
        
        // Constructor for the tree with the maximum expected value
        public RangeTree(int maxExpected, int type) {   
            maxExpected++;
            int len = Integer.bitCount(maxExpected)>1 ? Integer.highestOneBit(maxExpected)<<2 : Integer.highestOneBit(maxExpected)<<1;
            N = len/2;
            tree = new long[len];
            lazy = new long[len];
            if(tree[0]!=IDENTITY[type]){
                Arrays.fill(tree,IDENTITY[type]);           
                Arrays.fill(lazy,IDENTITY[type]);
            }
        }
    
        // Propagate the lazily accumulated values down the tree with query operator
        public void propagate(int node, int leftChild, int rightChild, int nodeFrom, int mid, int nodeTo, int type){
            tree[leftChild] = integrate(tree[leftChild],lazy[node],nodeFrom,mid, type);
            tree[rightChild] = integrate(tree[rightChild],lazy[node],mid+1,nodeTo, type);
            lazy[leftChild] = operation(lazy[leftChild],lazy[node],type);           
            lazy[rightChild] = operation(lazy[rightChild],lazy[node],type);         
            lazy[node] = IDENTITY[type];
        }
                
        // Update the values from the position i to j. Time complexity O(lg n)
        public void update(int i, int j, long newValue, int type) {
            update(1, 0, N-1, i, j,newValue, type);
        }
        
        private void update(int node, int nodeFrom, int nodeTo, int i, int j, long v, int type) {
            if (i <= nodeFrom && j >= nodeTo) { // Whole range needs to be updated
                tree[node] = integrate(tree[node], v, nodeFrom, nodeTo, type);
                lazy[node] = operation(lazy[node], v, type);
            } else if (j < nodeFrom || i > nodeTo) // No part of the range needs to be updated  
                return;        
            else { // Some part of the range needs to be updated
                int leftChild = 2 * node;
                int rightChild = leftChild+1;
                int mid = (nodeFrom + nodeTo) / 2;
                if(lazy[node]!=IDENTITY[type])
                    propagate(node, leftChild, rightChild, nodeFrom, mid, nodeTo, type);
                update(leftChild, nodeFrom, mid, i, j, v, type); // Search left child
                update(rightChild, mid+1, nodeTo, i, j, v, type); // Search right child
                tree[node] = operation(tree[leftChild], tree[rightChild],type); // Merge with the query operation
            }
        }
        
        // Query the range from i to j. Time complexity O(lg n)     
        public long query(int i, int j, int type) {                 
            return query(1, 0, N-1, i, j, type);
        }
                
        private long query(int node, int nodeFrom, int nodeTo, int i, int j, int type) {
            if (i <= nodeFrom && j >= nodeTo) // The whole range is part of the query
                return tree[node]; 
            else if (j < nodeFrom || i > nodeTo) // No part of the range belongs to the query 
                return IDENTITY[type];  
            else { // Partially within the range 
                int leftChild = 2*node;
                int rightChild = leftChild+1;
                int mid = (nodeFrom+nodeTo)/2;
                // Propagate lazy operations if necessary
                if(lazy[node]!=IDENTITY[type])
                    propagate(node, leftChild, rightChild, nodeFrom, mid, nodeTo, type);
                long a = query(leftChild, nodeFrom, mid, i, j, type);  // Search left child
                long b = query(rightChild, mid+1, nodeTo, i, j, type); // Search right child
                return operation(a, b, type);
            }
        }
    }

    public static void main(String[] args) {
        FastScanner sc = new FastScanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
                
        int[] a = new int[m];
        int[] b = new int[m];
        int[] q = new int[m];
        
        for(int i = 0; i < m; i++){
            a[i] = sc.nextInt()-1;
            b[i] = sc.nextInt()-1;
            q[i] = sc.nextInt();
        }
        
        RangeTree or = new RangeTree(n,0); // OR tree
        
        for(int i = 0; i < m; i++)
            or.update(a[i],b[i], q[i],0);
        
        RangeTree and = new RangeTree(n,1);
        
        for(int i = 0; i < n; i++)
            and.update(i, i, or.query(i,i,0), 1);
                
        boolean fail = false;       
        for(int i = 0; i < m; i++){
            long aux = and.query(a[i],b[i],1);
            if(aux!=q[i]){
                fail = true;
                break;
            }
        }
        
        PrintWriter out = new PrintWriter(System.out);
        if(!fail){
            out.println("YES");
            out.print(or.query(0,0,0));
            for(int i=1; i<n; i++){
                out.print(" "+or.query(i,i,0));
            }
            out.println();          

        } else {
            out.println("NO");
        }
        
        out.flush();
        out.close();

    }
    
    static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(File f) {
            try {
                br = new BufferedReader(new FileReader(f));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        public FastScanner(InputStream f) {
            br = new BufferedReader(new InputStreamReader(f));
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return null;
                st = new StringTokenizer(s);
            }
            return st.nextToken();
        }

        boolean hasMoreTokens() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return false;
                st = new StringTokenizer(s);
            }
            return true;
        }

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

        long nextLong() {
            return Long.parseLong(next());
        }
        
        double nextDouble(){
            return Double.parseDouble(next());
        }
    }

}
