#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;

struct maxflow {
  struct edge;
  using iter = vector<edge>::iterator;

  struct edge {
    int v, c;
    iter nxt;
  };

  vector<edge> pool;
  iter last, null;
  vector<iter> a, b;
  vector<int> d;

  iter new_edge(int v, int c, iter nxt) {
    iter p = last++;
    *p = edge{v, c, nxt};
    return p;
  }

  void add_edge(int u, int v, int c) {
    a[u] = new_edge(v, c, a[u]);
    a[v] = new_edge(u, 0, a[v]);
  }

  void add_bidirection_edge(int u, int v, int c) {
    a[u] = new_edge(v, c, a[u]);
    a[v] = new_edge(u, c, a[v]);
  }

  iter dual(iter p) {
    return pool.begin() + ((p - pool.begin()) ^ 1);
  }

  int augment(int u, int t, int bound) {
    if (u == t) return bound;
    int ret = 0;
    for (iter& it = b[u]; it != null && ret < bound; it = it->nxt) {
      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;
        dual(it)->c += aug;
      }
    }
    if (ret == 0) d[u] = -1;
    return ret;
  }

  bool path(int s, int t) {
    fill(d.begin(), d.end(), -1);
    d[s] = 0;
    queue<int> Q;
    Q.push(s);
    while (!Q.empty()) {
      int u = Q.front();
      Q.pop();
      for (iter it = a[u]; it != null; it = it->nxt) {
        if (it->c && d[it->v] == -1) {
          Q.push(it->v);
          d[it->v] = d[u] + 1;
          if (it->v == t) return true;
        }
      }
    }
    return false;
  }

  int n;
  void init(int n, int m) {
    this->n = n;
    pool.resize(m * 2 + 1);
    last = pool.begin();
    null = pool.end();
    a.assign(n, null);
    b.assign(n, null);
    d.resize(n);
  }

  int dinic(int s, int t) {
    int ret = 0;
    while (path(s, t)) {
      copy(a.begin(), a.end(), b.begin());
      while (int aug = augment(s, t, INF)) {
        ret += aug;
      }
    }
    return ret;
  }

};

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 flow;
  flow.init(len + 2, n * 2);
  int ret = 0;
  for (int i = 0; i < n; ++i) {
    if (a[i] == i && b[i] == i) {
      ++ret;
    } else if (a[i] != i && b[i] == i) {
      flow.add_edge(ca[i], t, 1);
    } else if (a[i] == i && b[i] != i) {
      flow.add_edge(s, cb[i], 1);
    } else {
      if (a[i] == b[i]) {
        flow.add_bidirection_edge(ca[i], cb[i], 1);
      } else {
        flow.add_edge(ca[i], cb[i], 1);
      }
    }
  }
  ret += flow.dinic(s, t);
  printf("%d\n", n - ret);
  return 0;
}


Measured memory_bytes: 11392