#include <bits/stdc++.h>
using namespace std;
class TaskD {
 public:
  bool match(int a, int b) { return a < 0 || a == b; }
  bool dfs(int m, int n, const vector<vector<bool>>& g, vector<int>& lmatch,
           vector<int>& rmatch, vector<bool>& mark, int at) {
    mark[at] = true;
    for (int i = 0; i < n; ++i)
      if (g[at][i] && rmatch[i] < 0) {
        rmatch[i] = at;
        lmatch[at] = i;
        return true;
      }
    for (int i = 0; i < n; ++i)
      if (g[at][i] && !mark[rmatch[i]] &&
          dfs(m, n, g, lmatch, rmatch, mark, rmatch[i])) {
        rmatch[i] = at;
        lmatch[at] = i;
        return true;
      }
    return false;
  }
  vector<int> matching(int m, int n, const vector<vector<bool>>& g) {
    vector<int> lmatch(m, -1);
    vector<int> rmatch(n, -1);
    vector<bool> mark(m, false);
    for (int i = 0; i < m; ++i) {
      if (dfs(m, n, g, lmatch, rmatch, mark, i)) {
        mark = vector<bool>(m, false);
      }
    }
    return lmatch;
  }
  vector<vector<int>> cycles;
  vector<vector<int>> pres;
  vector<int> solveOneTry(int n, const vector<int>& precycle,
                          const vector<int>& cycle, const vector<int>& lenCount,
                          const vector<vector<int>>& pureCycle,
                          const vector<int>& maxPre) {
    cycles = vector<vector<int>>(n + 1);
    pres = vector<vector<int>>(n + 1);
    int m = 0;
    for (int i = 1; i <= n; ++i) {
      for (int j = 0; j < lenCount[i] * i - pureCycle[i].size(); ++j) {
        cycles[i].push_back(m++);
      }
      for (int j = 1; j <= maxPre[i]; ++j) {
        pres[i].push_back(m++);
      }
    }
    if (m > n) {
      vector<int> res(1, -2);
      return res;
    }
    vector<vector<bool>> g(m, vector<bool>(n, false));
    for (int i = 1; i <= n; ++i) {
      for (int j : cycles[i]) {
        for (int k = 0; k < n; ++k) {
          if (precycle[k] == 0 && cycle[k] >= 0) continue;
          g[j][k] = match(precycle[k], 0) && match(cycle[k], i);
        }
      }
      for (int j = 0; j < pres[i].size(); ++j) {
        for (int k = 0; k < n; ++k) {
          if (precycle[k] == 0 && cycle[k] >= 0) continue;
          g[pres[i][j]][k] = match(precycle[k], j + 1) && match(cycle[k], i);
        }
      }
    }
    vector<int> match = matching(m, n, g);
    for (int x : match)
      if (x < 0) {
        vector<int> res(1, -2);
        return res;
      }
    for (int i = 1; i <= n; ++i) {
      for (int& x : cycles[i]) {
        x = match[x];
      }
      for (int y : pureCycle[i]) {
        cycles[i].push_back(y);
      }
      for (int& x : pres[i]) {
        x = match[x];
      }
    }
    vector<int> res(n, -1);
    for (int i = 1; i <= n; ++i) {
      for (int j = 0; j < lenCount[i]; ++j) {
        for (int k = 0; k < i; ++k) {
          res[cycles[i][j * i + k]] = cycles[i][j * i + ((k + 1) % i)];
        }
      }
      for (int j = 0; j < pres[i].size(); ++j) {
        res[pres[i][j]] = (j == 0) ? cycles[i][0] : pres[i][j - 1];
      }
    }
    return res;
  }
  vector<int> innerSolve(int n, const vector<int>& precycle,
                         const vector<int>& cycle) {
    vector<int> lenCount(n + 1, 0);
    vector<vector<int>> pureCycle(n + 1);
    vector<int> maxPre(n + 1, 0);
    int maxOverallPre = 0;
    for (int i = 0; i < n; ++i) {
      maxOverallPre = max(maxOverallPre, precycle[i]);
      if (cycle[i] < 0) continue;
      if (precycle[i] == 0) {
        ++lenCount[cycle[i]];
        pureCycle[cycle[i]].push_back(i);
      } else if (precycle[i] > 0) {
        maxPre[cycle[i]] = max(maxPre[cycle[i]], precycle[i]);
      }
    }
    for (int i = 0; i < n; ++i) {
      if (cycle[i] < 0) continue;
      lenCount[cycle[i]] = max(lenCount[cycle[i]], 1);
    }
    bool any = false;
    for (int i = 1; i <= n; ++i) {
      lenCount[i] = (lenCount[i] + i - 1) / i;
      any |= lenCount[i] > 0;
    }
    if (!any) {
      ++lenCount[1];
    }
    int maxExistingPre = 0;
    for (int i = 1; i <= n; ++i) {
      maxExistingPre = max(maxExistingPre, maxPre[i]);
    }
    vector<int> res =
        solveOneTry(n, precycle, cycle, lenCount, pureCycle, maxPre);
    if (res[0] == -2) return res;
    int maxi = 0;
    for (int i = 1; i <= n; ++i) {
      if (lenCount[i] > 0) {
        if (maxi == 0 || maxPre[i] > maxPre[maxi]) maxi = i;
      }
    }
    if (maxExistingPre < maxOverallPre) {
      bool found = false;
      for (maxi = 1; maxi <= n && !found; ++maxi)
        if (lenCount[maxi] > 0) {
          int saved = maxPre[maxi];
          maxPre[maxi] = maxOverallPre;
          res = solveOneTry(n, precycle, cycle, lenCount, pureCycle, maxPre);
          if (res[0] != -2) {
            found = true;
            break;
          }
          maxPre[maxi] = saved;
        }
      if (!found) {
        res = vector<int>(1, -2);
        return res;
      }
    }
    for (int i = 0; i < n; ++i)
      if (res[i] < 0) {
        int pc = precycle[i];
        int c = cycle[i];
        if (c < 0) {
          if (pc == 0) {
            c = 1;
          } else {
            c = maxi;
          }
        }
        if (pc < 0) {
          pc = 1;
        }
        if (pc == 0) {
          assert(c == 1);
          res[i] = i;
        } else {
          if (pc == 1) {
            res[i] = cycles[c][0];
          } else {
            res[i] = pres[c][pc - 2];
          }
        }
      }
    return res;
  }
  void solve(istream& in, ostream& out) {
    srand(123);
    for (int it = 0; it < 0; ++it) {
      int n = rand() % 20 + 1;
      vector<int> res(n);
      for (int i = 0; i < n; ++i) res[i] = rand() % n;
      vector<int> pc(n, -1);
      vector<int> c(n, -1);
      for (int i = 0; i < n; ++i) {
        vector<int> seen(n, -1);
        int cur = i;
        int at = 0;
        while (seen[cur] < 0) {
          seen[cur] = at;
          ++at;
          cur = res[cur];
        }
        pc[i] = seen[cur];
        c[i] = at - seen[cur];
      }
      for (int i = 0; i < n; ++i) {
        if (rand() % 5 > 0) pc[i] = -1;
        if (rand() % 5 > 0) c[i] = -1;
      }
      res = innerSolve(n, pc, c);
      if (res[0] >= 0) {
        for (int i = 0; i < n; ++i) {
          vector<int> seen(n, -1);
          int cur = i;
          int at = 0;
          while (seen[cur] < 0) {
            seen[cur] = at;
            ++at;
            cur = res[cur];
          }
          int cpc = seen[cur];
          int cc = at - seen[cur];
          assert(match(pc[i], cpc) && match(c[i], cc));
        }
      } else {
        innerSolve(n, pc, c);
        assert(false);
      }
    }
    int n;
    in >> n;
    vector<int> precycle(n, -1);
    vector<int> cycle(n, -1);
    for (int i = 0; i < n; ++i) {
      string s;
      in >> s;
      if (s != "?") {
        precycle[i] = atoi(s.c_str());
      }
      in >> s;
      if (s != "?") {
        cycle[i] = atoi(s.c_str());
      }
    }
    vector<int> res = innerSolve(n, precycle, cycle);
    if (res[0] >= 0) {
      for (int i = 0; i < n; ++i) {
        vector<int> seen(n, -1);
        int cur = i;
        int at = 0;
        while (seen[cur] < 0) {
          seen[cur] = at;
          ++at;
          cur = res[cur];
        }
        int pc = seen[cur];
        int c = at - seen[cur];
        assert(match(precycle[i], pc) && match(cycle[i], c));
      }
    }
    for (int i = 0; i < res.size(); ++i) {
      if (i > 0) out << " ";
      out << (res[i] + 1);
    }
    out << "\n";
  }
};
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  TaskD solver;
  std::istream& in(std::cin);
  std::ostream& out(std::cout);
  solver.solve(in, out);
  return 0;
}
