// twitter ROMってたら見つけたコード
// Dinicのdfsがバグっていそう
// nowが0になってもiterが進んでしまう
//#define NDEBUG
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <vector>

namespace n91 {

  using i8 = std::int_fast8_t;
  using i32 = std::int_fast32_t;
  using i64 = std::int_fast64_t;
  using u8 = std::uint_fast8_t;
  using u32 = std::uint_fast32_t;
  using u64 = std::uint_fast64_t;
  using isize = std::ptrdiff_t;
  using usize = std::size_t;

  constexpr usize operator"" _z(unsigned long long x) noexcept {
    return static_cast<usize>(x);
  }

  template <class T> class integral_iterator {
  public:
    using difference_type = T;
    using value_type = T;
    using pointer = const value_type*;
    using reference = value_type;
    using iterator_category = std::random_access_iterator_tag;

  private:
    using self_type = integral_iterator<value_type>;
    value_type i;

  public:
    constexpr integral_iterator() noexcept : i() {}
    explicit constexpr integral_iterator(const value_type i) noexcept : i(i) {}
    constexpr self_type operator++(int) noexcept { return self_type(i++); }
    constexpr self_type operator--(int) noexcept { return self_type(i--); }
    constexpr self_type operator[](const difference_type rhs) const noexcept {
      return self_type(i + rhs);
    }
    constexpr self_type& operator++() noexcept {
      ++i;
      return *this;
    }
    constexpr self_type& operator--() noexcept {
      --i;
      return *this;
    }
    constexpr reference operator*() const noexcept { return i; }
    constexpr self_type operator+(const difference_type rhs) const noexcept {
      return self_type(i + rhs);
    }
    constexpr self_type operator-(const difference_type rhs) const noexcept {
      return self_type(i - rhs);
    }
    constexpr difference_type operator-(const self_type rhs) const noexcept {
      return i - rhs.i;
    }
    constexpr bool operator<(const self_type rhs) const noexcept {
      return i < rhs.i;
    }
    constexpr bool operator<=(const self_type rhs) const noexcept {
      return i <= rhs.i;
    }
    constexpr bool operator>(const self_type rhs) const noexcept {
      return i > rhs.i;
    }
    constexpr bool operator>=(const self_type rhs) const noexcept {
      return i >= rhs.i;
    }
    constexpr bool operator==(const self_type rhs) const noexcept {
      return i == rhs.i;
    }
    constexpr bool operator!=(const self_type rhs) const noexcept {
      return i != rhs.i;
    }
    constexpr self_type& operator+=(const difference_type rhs) noexcept {
      i += rhs;
      return *this;
    }
    constexpr self_type& operator-=(const difference_type rhs) noexcept {
      i -= rhs;
      return *this;
    }
  };
  template <class T>
  constexpr integral_iterator<T> make_int_itr(const T i) noexcept {
    return integral_iterator<T>(i);
  }
  class rep {
    const usize f, l;

  public:
    constexpr rep(const usize f, const usize l) noexcept : f(f), l(l) {}
    constexpr auto begin() const noexcept { return make_int_itr(f); }
    constexpr auto end() const noexcept { return make_int_itr(l); }
  };
  class revrep {
    const usize f, l;

  public:
    revrep(const usize f, const usize l) noexcept : f(l), l(f) {}
    auto begin() const noexcept {
      return std::make_reverse_iterator(make_int_itr(f));
    }
    auto end() const noexcept {
      return std::make_reverse_iterator(make_int_itr(l));
    }
  };
  template <class T> auto md_vec(const usize n, const T& value) {
    return std::vector<T>(n, value);
  }
  template <class... Args> auto md_vec(const usize n, Args... args) {
    return std::vector<decltype(md_vec(args...))>(n, md_vec(args...));
  }
  template <class T> constexpr T difference(const T& a, const T& b) {
    return a < b ? b - a : a - b;
  }
  template <class T> T scan() {
    T ret;
    std::cin >> ret;
    return ret;
  }

} // namespace n91
#include <cstdint>

namespace n91 {

  constexpr std::uint_fast64_t totient(std::uint_fast64_t x) noexcept {
    using u64 = std::uint_fast64_t;
    u64 ret = x;
    for (u64 i = static_cast<u64>(2); i * i <= x; ++i) {
      if (x % i == static_cast<u64>(0)) {
        ret -= ret / i;
        x /= i;
        while (x % i == static_cast<u64>(0)) {
          x /= i;
        }
      }
    }
    if (x != static_cast<u64>(1)) {
      ret -= ret / x;
    }
    return ret;
  }

  template <std::uint_fast64_t Modulus,
    std::uint_fast64_t InverseExp =
    totient(Modulus) - static_cast<std::uint_fast64_t>(1)>
    class modint {
    using u64 = std::uint_fast64_t;

    static_assert(Modulus < static_cast<u64>(1) << static_cast<u64>(32),
      "Modulus must be less than 2**32");

    u64 a;

    constexpr modint& negate() noexcept {
      if (a != static_cast<u64>(0)) {
        a = Modulus - a;
      }
      return *this;
    }

    public:
      constexpr modint(const u64 x = static_cast<u64>(0)) noexcept
        : a(x% Modulus) {}
      constexpr u64& value() noexcept { return a; }
      constexpr const u64& value() const noexcept { return a; }
      constexpr modint operator+() const noexcept { return modint(*this); }
      constexpr modint operator-() const noexcept { return modint(*this).negate(); }
      constexpr modint operator+(const modint rhs) const noexcept {
        return modint(*this) += rhs;
      }
      constexpr modint operator-(const modint rhs) const noexcept {
        return modint(*this) -= rhs;
      }
      constexpr modint operator*(const modint rhs) const noexcept {
        return modint(*this) *= rhs;
      }
      constexpr modint operator/(const modint rhs) const noexcept {
        return modint(*this) /= rhs;
      }
      constexpr modint& operator+=(const modint rhs) noexcept {
        a += rhs.a;
        if (a >= Modulus) {
          a -= Modulus;
        }
        return *this;
      }
      constexpr modint& operator-=(const modint rhs) noexcept {
        if (a < rhs.a) {
          a += Modulus;
        }
        a -= rhs.a;
        return *this;
      }
      constexpr modint& operator*=(const modint rhs) noexcept {
        a = a * rhs.a % Modulus;
        return *this;
      }
      constexpr modint& operator/=(modint rhs) noexcept {
        u64 exp = InverseExp;
        while (exp) {
          if (exp % static_cast<u64>(2) != static_cast<u64>(0)) {
            *this *= rhs;
          }
          rhs *= rhs;
          exp /= static_cast<u64>(2);
        }
        return *this;
      }
      constexpr bool operator==(const modint rhs) const noexcept {
        return a == rhs.a;
      }
      constexpr bool operator!=(const modint rhs) const noexcept {
        return a != rhs.a;
      }
  };

  template <class T, std::uint_fast64_t v> class modint_constant {
  public:
    static constexpr T value = static_cast<T>(v);

    using value_type = T;
  };

} // namespace n91
template <class T> void multiple_transform(::std::vector<T>& a) {
  int n = a.size();
  ::std::vector<bool> sieve(n, true);
  for (int p = 2; p < n; ++p) {
    if (sieve[p]) {
      for (int k = (n - 1) / p; k != 0; --k) {
        sieve[k * p] = false;
        a[k] += a[k * p];
      }
    }
  }
  for (int i = 0; ++i != n;) {
    a[i] += a[0];
  }
}

template <class T> void inverse_multiple_transform(::std::vector<T>& a) {
  int n = a.size();
  ::std::vector<bool> sieve(n, true);
  for (int i = 0; ++i != n;) {
    a[i] -= a[0];
  }
  for (int p = 2; p < n; ++p) {
    if (sieve[p]) {
      for (int k = 1; k * p < n; ++k) {
        sieve[k * p] = false;
        a[k] -= a[k * p];
      }
    }
  }
}
#ifndef NIMI_GRAPH
#define NIMI_GRAPH

#include <vector>

namespace nimi {
  struct base_edge {
    int from;
    int to;
    base_edge(int from, int to) : from(from), to(to) {}
  };

  template <class T> struct edge : public base_edge {
    T val;
    edge(int from, int to, T v) : base_edge(from, to), val(v) {}
  };

  template <> struct edge<void> : public base_edge {
    edge(int from, int to) : base_edge(from, to) {}
  };
  template <class C> struct maxflow_edge : public base_edge {
    C cap;
    std::size_t rev;
    maxflow_edge(int from, int to, C cap, std::size_t rev)
      : base_edge(from, to), cap(cap), rev(rev) {}
  };

  template <class T>
  struct directed_graph : public std::vector<std::vector<edge<T>>> {
    directed_graph(std::size_t n) : std::vector<std::vector<edge<T>>>(n) {}
    void add_edge(const edge<T>& e) { this->at(e.from).push_back(e); }
  };

  template <class T>
  struct undirected_graph : public std::vector<std::vector<edge<T>>> {
    undirected_graph(std::size_t n) : std::vector<std::vector<edge<T>>>(n) {}
    void add_edge(const edge<T>& e) {
      this->at(e.from).push_back(e);
      edge<T> re = e;
      std::swap(re.from, re.to);
      this->at(e.to).push_back(re);
    }
  };

  template <class C>
  struct maxflow_graph : public std::vector<std::vector<maxflow_edge<C>>> {
    maxflow_graph(std::size_t n) : std::vector<std::vector<maxflow_edge<C>>>(n) {}
    void add_edge(int from, int to, C cap, std::size_t rev_cap = 0) {
      this->at(from).push_back(
        maxflow_edge<C>(from, to, cap, this->at(to).size()));
      this->at(to).push_back(
        maxflow_edge<C>(to, from, rev_cap, this->at(from).size() - 1));
    }
  };
} // namespace nimi

#endif
#include <functional>
#include <limits>
#include <queue>
#include <vector>

namespace nimi {
  template <class C>
  C dinic(nimi::maxflow_graph<C>& g, std::size_t s, std::size_t t) {
    C inf = std::numeric_limits<C>::max();
    C ans = 0;
    std::size_t n = g.size();

    std::vector<int> level(n);
    std::vector<std::size_t> iter(n);

    std::function<void(void)> g_level = [&]() {
      level.assign(n, -1);
      std::queue<int> que;
      que.push(s);
      level[s] = 0;
      while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (const auto& e : g[v]) {
          if (e.cap > 0 && level[e.to] == -1) {
            level[e.to] = level[e.from] + 1;
            que.push(e.to);
          }
        }
      }
    };

    const auto dinic_dfs = [&](const auto &dfs, int v, C f) {
      if (v == t)
        return f;
      C now = f;

      for (std::size_t& i = iter[v]; i < g[v].size(); i++) {
        auto& e = g[v][i];
        if (e.cap > 0 && level[e.to] > level[e.from]) {
          C ff = dfs(dfs, e.to, std::min(now, e.cap));
          e.cap -= ff;
          g[e.to][e.rev].cap += ff;
          now -= ff;
          //add
          if (now == 0) return f - now;
        }
      }
      return f - now;
    };

    while (1) {
      g_level();
      if (level[t] < 0)
        break;
      C f;
      iter.assign(n, 0);
      while ((f = dinic_dfs(dinic_dfs, s, inf)) > 0) {
        ans += f;
      }
    }

    return ans;
  }
} // namespace nimi
#include <cassert>
#include <cstddef>
#include <utility>
#include <vector>

namespace n91 {

  class incremental_connectivity {
  protected:
    class node_type;

  public:
    using container_type = std::vector<node_type>;
    using size_type = typename container_type::size_type;
    class connected_component {
      friend incremental_connectivity;
      const node_type& root;
      constexpr connected_component(const node_type& root) noexcept
        : root(root) {}

    public:
      constexpr size_type representative() const noexcept { return root.parent; }
      constexpr size_type size() const noexcept { return root.size; }
      constexpr bool operator==(const connected_component& rhs) const noexcept {
        return &root == &rhs.root;
      }
      constexpr bool operator!=(const connected_component& rhs) const noexcept {
        return &root != &rhs.root;
      }
    };

  protected:
    class node_type {
    public:
      size_type parent, size;
    };
    container_type tree;

  public:
    incremental_connectivity() : tree() {}
    explicit incremental_connectivity(const size_type size) : tree(size, { 0, 1 }) {
      for (size_type i = 0; i < size; ++i)
        tree[i].parent = i;
    }

    bool empty() const { return tree.empty(); }
    size_type size() const { return tree.size(); }

    connected_component find_cc(size_type x) {
      while (tree[x].parent != x) {
        x = tree[x].parent = tree[tree[x].parent].parent;
      }
      return connected_component(tree[x]);
    }

    std::pair<size_type, size_type> unite(size_type x, size_type y) {
      assert(x < size());
      assert(y < size());
      x = find_cc(x).representative();
      y = find_cc(y).representative();
      if (x != y) {
        if (tree[x].size < tree[y].size)
          std::swap(x, y);
        tree[x].size += tree[y].size;
        tree[y].parent = x;
      }
      return { x, y };
    }
  };

} // namespace n91

#include <algorithm>
#include <iostream>
#include <utility>

namespace n91 {

  void main_() {
    const usize n = scan<usize>();
    std::vector<usize> p(n), q(n);
    incremental_connectivity uf(n * 2);
    for (auto& e : p) {
      std::cin >> e;
    }
    for (auto& e : q) {
      std::cin >> e;
    }
    for (int i = 0; i < n; ++i) {
      uf.unite(i, p[i]);
      uf.unite(n + i, n + q[i]);
    }
    nimi::maxflow_graph<i64> g(n * 2 + 2);
    usize src = n * 2;
    usize sink = n * 2 + 1;
    i64 ans = n;
    const auto get = [&](usize x) {
      return uf.find_cc(x).representative();
    };
    for (const auto i : rep(0_z, n)) {
      if (i == p[i]) {
        if (i == q[i]) {
          --ans;
        }
        else {
          g.add_edge(src, get(n + i), 1);
        }
      }
      else {
        if (i == q[i]) {
          g.add_edge(get(i), sink, 1);
        }
        else {
          if (p[i] != q[i]) {
            g.add_edge(get(i), get(n + i), 1);
          }
          else {
            g.add_edge(get(i), get(n + i), 1);
            g.add_edge(get(n + i), get(i), 1);
          }
        }
      }
    }
    std::cout << ans - nimi::dinic(g, src, sink) << std::endl;
  }

} // namespace n91

int main() {
  n91::main_();
  return 0;
}


Measured memory_bytes: 23936