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
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int tree[N << 2], lazy[N << 2];
int n, m;
int v[N], u[N], add[N];
void push_up(int rt) { tree[rt] = tree[rt << 1] & tree[rt << 1 | 1]; }
void push_down(int rt) {
  lazy[rt << 1] |= lazy[rt];
  lazy[rt << 1 | 1] |= lazy[rt];
  tree[rt << 1] |= lazy[rt];
  tree[rt << 1 | 1] |= lazy[rt];
  lazy[rt] = 0;
}
void build(int rt, int l, int r) {
  if (l == r) {
    tree[rt] = 0;
    return;
  }
  int mid = (l + r) >> 1;
  build(rt << 1, l, mid);
  build(rt << 1 | 1, mid + 1, r);
  push_up(rt);
}
void update(int L, int R, int val, int rt, int l, int r) {
  if (L <= l && r <= R) {
    tree[rt] |= val;
    lazy[rt] |= val;
    return;
  }
  push_down(rt);
  int mid = (l + r) >> 1;
  if (L <= mid) update(L, R, val, rt << 1, l, mid);
  if (R > mid) update(L, R, val, rt << 1 | 1, mid + 1, r);
  push_up(rt);
}
int query(int L, int R, int rt, int l, int r) {
  if (L <= l && r <= R) {
    return tree[rt];
  }
  push_down(rt);
  int mid = (l + r) >> 1;
  if (R <= mid)
    return query(L, R, rt << 1, l, mid);
  else if (L > mid)
    return query(L, R, rt << 1 | 1, mid + 1, r);
  else
    return query(L, mid, rt << 1, l, mid) &
           query(mid + 1, R, rt << 1 | 1, mid + 1, r);
}
int main() {
  while (scanf("%d%d", &n, &m) != EOF) {
    build(1, 1, n);
    for (int i = 0; i < m; ++i) {
      scanf("%d%d%d", &u[i], &v[i], &add[i]);
      update(u[i], v[i], add[i], 1, 1, n);
    }
    int flag = 1;
    for (int i = 0; i < m; ++i) {
      if (query(u[i], v[i], 1, 1, n) != add[i]) {
        puts("NO");
        flag = 0;
        break;
      }
    }
    if (flag) {
      puts("YES");
      for (int i = 1; i <= n; ++i)
        printf("%d%c", query(i, i, 1, 1, n), i == n ? '\n' : ' ');
    }
  }
  return 0;
}
