#define _USE_MATH_DEFINES
#include <array>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>
#include <complex>
#include <cmath>
#include <numeric>
#include <bitset>
#include <functional>
#include <random>
#include <ctime>

using namespace std;

#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << ": " << arg1 << endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');
  cerr.write(names, comma - names) << ": " << arg1 << " |";
  __f(comma + 1, args...);
}

typedef long long int64;
typedef pair<int, int> ii;
const int INF = 1 << 29;
const int MOD = 1e9 + 7;

#define SZ(x) (int)(x.size())

struct Edge {
  int v, c, f, dual;
  Edge() {}
  Edge(int v, int c, int dual) : v(v), c(c), dual(dual) { f = 0; }
};

template<size_t N>
struct maxflow {
  vector<Edge> a[N];
  vector<Edge>::iterator idx[N];
  int d[N];

  void add_edge(int u, int v, int c) {
    a[u].emplace_back(v, c, SZ(a[v]));
    a[v].emplace_back(u, 0, SZ(a[u]) - 1);
  }
  void add_bidirection_edge(int u, int v, int c) {
    a[u].emplace_back(v, c, SZ(a[v]));
    a[v].emplace_back(u, c, SZ(a[u]) - 1);
  }
  int augment(int u, int t, int bound) {
    if (u == t) return bound;
    int ret = 0;
    // current arc optimization
    for (auto it = a[u].begin(); it != a[u].end() && ret < bound; ++it) {
      if (it->c && d[it->v] == d[u] + 1) {
        int aug = augment(it->v, t, min(it->c, bound - ret));
        ret += aug;
        it->c -= aug;
        a[it->v][it->dual].c += aug;
      }
    }
    if (ret == 0) d[u] = -1;
    return ret;
  }
  int n;
  bool path(int s, int t) {
    fill(d, d + n, -1);
    d[s] = 0;
    queue<int> Q;
    Q.push(s);
    while (!Q.empty()) {
      int u = Q.front();
      Q.pop();
      for (auto& p : a[u]) {
        if (p.c && d[p.v] == -1) {
          Q.push(p.v);
          d[p.v] = d[u] + 1;
          if (p.v == t) return true;
        }
      }
    }
    return false;
  }
  void init(int n) {
    this->n = n;
    for (int i = 0; i < n; ++i) a[i].clear();
  }
  int dinic(int s, int t) {
    int ret = 0;
    while (path(s, t)) {
      // current arc optimization
      // for (int i = 0; i < n; ++i) idx[i] = a[i].begin();
      while (int aug = augment(s, t, INF)) {
        ret += aug;
      }
    }
    return ret;
  }
};

const int N = 2e5 + 10;

int main() {
  int n;
  scanf("%d", &n);
  vector<int> a(n), b(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
  }
  for (int i = 0; i < n; ++i) {
    scanf("%d", &b[i]);
  }
  vector<int> ca(n, -1), cb(n, -1);
  int len = 0;
  for (int i = 0; i < n; ++i) {
    if (ca[i] >= 0) continue;
    ca[i] = len++;
    for (int j = a[i]; j != i; j = a[j]) ca[j] = ca[i];
  }
  for (int i = 0; i < n; ++i) {
    if (cb[i] >= 0) continue;
    cb[i] = len++;
    for (int j = b[i]; j != i; j = b[j]) cb[j] = cb[i];
  }
  int s = len, t = s + 1;
  maxflow<N> flow;
  flow.init(len + 2);
  int ret = 0;
  map<ii, int> cnt;
  for (int i = 0; i < n; ++i) {
    if (a[i] == i && b[i] == i) {
      ++ret;
    } else if (a[i] != i && b[i] == i) {
      cnt[{ca[i], t}]++;
      // flow.add_edge(ca[i], t, 1);
    } else if (a[i] == i && b[i] != i) {
      cnt[{s, cb[i]}]++;
      // flow.add_edge(s, cb[i], 1);
    } else {
      if (a[i] == b[i]) {
        // flow.add_bidirection_edge(ca[i], cb[i], 1);
        cnt[{ca[i], cb[i]}]++;
        cnt[{cb[i], ca[i]}]++;
      } else {
        cnt[{ca[i], cb[i]}]++;
        // flow.add_edge(ca[i], cb[i], 1);
      }
    }
  }
  for (auto& it : cnt) {
    int x = it.first.first, y = it.first.second;
    flow.add_edge(x, y, it.second);
  }
  ret += flow.dinic(s, t);
  printf("%d\n", n - ret);
  return 0;
}


Measured memory_bytes: 22784