#include #include using namespace std; using namespace atcoder; class DSU_IDX{ private: int n; vector par_size, num_pair; public: int score; DSU_IDX():n(0),score(0){} DSU_IDX(int size):n(size),score(0),par_size(size,-1),num_pair(size,0){} int root(int v){ if(par_size[v] < 0)return v; while(par_size[par_size[v]] >= 0){ int ps = par_size[v]; par_size[v] = par_size[ps]; v = ps; } return par_size[v]; } // 連結の際にスコアを更新する void unite(int u,int v){ int ru = root(u),rv = root(v); if(ru == rv)return; score -= sub_score(ru) + sub_score(rv); if(par_size[ru] > par_size[rv]){ par_size[rv] += par_size[ru]; par_size[ru] = rv; num_pair[rv] += num_pair[ru]; score += sub_score(rv); } else{ par_size[ru] += par_size[rv]; par_size[rv] = ru; num_pair[ru] += num_pair[rv]; score += sub_score(ru); } } // v を含む連結成分の表す区間に配置可能なペアを増加 // スコアを更新する void add_pair(int v){ int rv = root(v); score -= sub_score(rv); num_pair[rv]++; score += sub_score(rv); } bool same(int u,int v){ return root(u) == root(v); } int size(int v){ return -par_size[root(v)]; } int sub_score(int v){ return min(-par_size[root(v)],num_pair[root(v)]); } }; class DSU_AB{ private: int n; vector par_size,L,R; public: DSU_AB():n(0){} DSU_AB(int size):n(size),par_size(size,-1),L(size),R(size){ for(int i=0;i= 0){ int ps = par_size[v]; par_size[v] = par_size[ps]; v = ps; } return par_size[v]; } void unite(int u,int v){ int ru = root(u),rv = root(v); if(ru == rv)return; if(par_size[ru] > par_size[rv]){ par_size[rv] += par_size[ru]; par_size[ru] = rv; L[rv] = min(L[rv],L[ru]); R[rv] = max(R[rv],R[ru]); } else{ par_size[ru] += par_size[rv]; par_size[rv] = ru; L[ru] = min(L[rv],L[ru]); R[ru] = max(R[rv],R[ru]); } } bool same(int u,int v){ return root(u) == root(v); } int size(int v){ return -par_size[root(v)]; } int left(int v){ return L[root(v)]; } int right(int v){ return R[root(v)]; } }; int main(){ int n; cin >> n; vectora(n),b(n),z(n); for(int i=0;i> a[i]; for(int i=0;i> b[i]; for(int i=0;i> z[i]; vectorida(n),idb(n); for(int i=0;ipos_left(n),l(n),r(n); for(int i=0;i>mid(n,queue()); // mid[i] : k = i で判定を行うペア番号の集合 for(int _ = 0;_ < 18;_++){ for(int i=0;i1){ mid[(l[i]+r[i])/2].push(i); } } DSU_AB ufa(n),ufb(n); // i を含む連結成分には、a で i が動ける区間 [l, r] を持たせる // 同じ連結成分の要素は動ける区間も同じ for(int k=0;k0&&a[ia-1]<=k)ufa.unite(ia-1,ia); if(ia+10&&b[ib-1]<=k)ufb.unite(ib-1,ib); if(ib+1less_k(n); // less_k[i] = (a_i <= k) + (b_i <= k) DSU_IDX ufi(n); // インデックス [1,n] を管理する for(int k=0;k0&&less_k[ia-1]==2)ufi.unite(ia-1,ia); if(ia+10&&less_k[ib-1]==2)ufi.unite(ib-1,ib); if(ib+1