#include <bits/stdc++.h>
#pragma warning(disable : 4996)
template <typename T>
T min(T x, T y) {
  return x < y ? x : y;
}
template <typename T>
T max(T x, T y) {
  return x > y ? x : y;
};
const long long MAXN = 500005;
const int INF = 2000000000;
struct tree {
 private:
  int l;
  int r;
  int mn;
  tree *lson;
  tree *rson;

 public:
  tree() {
    l = r = 0;
    mn = INF;
    lson = rson = NULL;
  }
  void build(int L, int R) {
    l = L;
    r = R;
    if (l == r) return;
    int mid = (l + r) / 2;
    lson = new tree;
    rson = new tree;
    lson->build(l, mid);
    rson->build(mid + 1, r);
  }
  void update(int L, int R, int k) {
    if (l >= L && r <= R) {
      mn = min(mn, k);
      return;
    }
    int mid = (l + r) / 2;
    if (L <= mid) lson->update(L, R, k);
    if (R > mid) rson->update(L, R, k);
  }
  int query(int id) {
    if (l == r) return mn;
    int mid = (l + r) / 2;
    if (id <= mid) return min(mn, lson->query(id));
    return min(mn, rson->query(id));
  }
};
struct Tree {
 private:
  int l;
  int r;
  int mx;
  Tree *lson;
  Tree *rson;

 public:
  Tree() {
    l = r = 0;
    mx = 0;
    lson = rson = NULL;
  }
  void build(int L, int R) {
    l = L;
    r = R;
    if (l == r) return;
    int mid = (l + r) / 2;
    lson = new Tree;
    rson = new Tree;
    lson->build(l, mid);
    rson->build(mid + 1, r);
  }
  void fixup() { mx = max(lson->mx, rson->mx); }
  void update(int id, int k) {
    if (l == r) {
      mx = k;
      return;
    }
    int mid = (l + r) / 2;
    if (id <= mid)
      lson->update(id, k);
    else
      rson->update(id, k);
    fixup();
  }
  int query(int L, int R) {
    if (l >= L && r <= R) return mx;
    int mid = (l + r) / 2;
    if (R <= mid) return lson->query(L, R);
    if (L > mid) return rson->query(L, R);
    return max(lson->query(L, R), rson->query(L, R));
  }
};
int N, M;
int ty[MAXN], x[MAXN], y[MAXN], z[MAXN];
int val[MAXN], cnt[MAXN], num, temp[MAXN];
int mx[MAXN];
tree T1;
Tree T2;
int pos(int w) { return std::lower_bound(val + 1, val + num + 1, w) - val; }
void init() {
  scanf("%d %d", &N, &M);
  T1.build(1, N);
  T2.build(1, N);
  memset(mx, -1, sizeof(mx));
  for (int i = 1; i <= M; i++) {
    scanf("%d %d %d", ty + i, x + i, y + i);
    if (ty[i] == 1) {
      scanf("%d", z + i);
      val[++num] = z[i];
      T1.update(x[i], y[i], z[i]);
    } else if (mx[x[i]] == -1)
      mx[x[i]] = T1.query(x[i]);
  }
  val[++num] = INF;
  std::sort(val + 1, val + num + 1);
  for (int i = 1; i <= N; i++)
    if (mx[i] == -1) mx[i] = T1.query(i);
  for (int i = 1; i <= N; i++) {
    T2.update(i, mx[i]);
    cnt[pos(mx[i])]++;
  }
}
void solve() {
  for (int i = 1; i <= M; i++) {
    if (ty[i] == 1) {
      if (T2.query(x[i], y[i]) == z[i]) continue;
      printf("NO\n");
      return;
    } else
      T2.update(x[i], y[i]);
  }
  if (cnt[num] <= 1) {
    for (int i = 1; i <= N; i++) {
      if (mx[i] == INF) continue;
      int p = pos(mx[i]);
      if (temp[p]) {
        int t = 1;
        while (t * 2 <= mx[i]) t *= 2;
        mx[i] = t - 1;
      }
      temp[p]++;
    }
    if (cnt[num] == 1) {
      int OR = 0, t = 0;
      for (int i = 1; i <= N; i++)
        if (mx[i] == INF)
          t = i;
        else
          OR |= mx[i];
      int tmp = 0;
      for (int i = 30; i >= 0; i--) {
        if (!(OR & (1 << i)) && tmp + (1 << i) <= 1000000000) tmp += (1 << i);
      }
      mx[t] = tmp;
    }
  } else {
    bool flag = false;
    for (int i = 1; i <= N; i++)
      if (mx[i] == INF) {
        if (!flag)
          mx[i] = (1 << 29) - 1;
        else
          mx[i] = 1000000000;
        flag = true;
      }
  }
  printf("YES\n");
  for (int i = 1; i <= N; i++) printf("%d ", mx[i]);
}
int main() {
  init();
  solve();
  return 0;
}
