【题目】
原题地址
给定一棵 n n n个点的树,每个点分别有 0 0 0~ n − 1 n-1 n−1的点权。有 q q q个操作:
【解题思路】
由 m e x mex mex的定义,我们知道我们只需要知道前 i i i个权是否在一条路径上,这个显然是满足二分性的,那么问题就在于如何维护这个东西。假设 0 0 0~ i i i和 i + 1 i+1 i+1~ j j j分别在同一条路径上,那么问题就可以转化为这两条路径是否能连在一起。那么这个问题我们先求出 dfs \text{dfs} dfs,然后用求路径交的类似方法就可以维护合并了。
整体我们显然可以用线段树来维护。时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
【参考代码】
#include
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+10,M=N*4;
int Q,n,ind,ans;
int fc[25],dep[N],in[N],out[N],a[N],fa[21][N];
vector<int>g[N];
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
void dfs(int x)
{
in[x]=++ind;
for(int i=1;fc[i]<=dep[x];++i) fa[i][x]=fa[i-1][fa[i-1][x]];
for(int i=0;i<(int)g[x].size();++i)
{
int v=g[x][i];
fa[0][v]=x;dep[v]=dep[x]+1;
dfs(g[x][i]);
}
out[x]=++ind;
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int t=dep[x]-dep[y],i=0;t;++i)
if(t&fc[i]) x=fa[i][x],t^=fc[i];
for(int i=19;~i;--i) if(fa[i][x]^fa[i][y])
x=fa[i][x],y=fa[i][y];
return x==y?x:fa[0][x];
}
namespace Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
pii t[M],res;
bool anc(int x,int y){return in[x]<=in[y] && out[x]>=out[y];}
pii check(pii x,int y)
{
if(!x.fi || !y) return mkp(0,0);
if(anc(x.fi,x.se)) swap(x.fi,x.se);
if(anc(x.se,x.fi))
{
if(anc(x.fi,y)) return mkp(x.se,y);
if(anc(x.se,y))
{
if(anc(y,x.fi)) return x;
if(lca(x.fi,y)==x.se) return mkp(x.fi,y);
return mkp(0,0);
}
return mkp(y,x.fi);
}
if(anc(x.fi,y)) return mkp(y,x.se);
if(anc(x.se,y)) return mkp(y,x.fi);
if(!anc(y,x.fi) && !anc(y,x.se)) return mkp(0,0);
if(!anc(lca(x.fi,x.se),y)) return mkp(0,0);
return x;
}
pii merge(pii x,pii y)
{
if(x.fi==-1) return y;
x=check(x,y.fi);x=check(x,y.se);
return x;
}
void update(int x,int l,int r,int p,int v)
{
if(l==r){t[x]=mkp(v,v);return;}
int mid=(l+r)>>1;
if(p<=mid) update(ls,l,mid,p,v);
else update(rs,mid+1,r,p,v);
t[x]=merge(t[ls],t[rs]);
}
bool query(int x,int l,int r)
{
pii tmp=merge(res,t[x]);
if(tmp.fi){res=tmp;ans=r;return 1;}
if(l==r) return 0;
int mid=(l+r)>>1;
if(query(ls,l,mid)) query(rs,mid+1,r);
return 0;
}
};
using namespace Segment;
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF1083C.in","r",stdin);
freopen("CF1083C.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;++i) a[i]=read()+1;
for(int i=2;i<=n;++i) g[read()].pb(i);
fc[0]=1;for(int i=1;i<=20;++i)fc[i]=fc[i-1]<<1;
dfs(1);
for(int i=1;i<=n;++i) update(1,1,n,a[i],i);
Q=read();
while(Q--)
{
int op=read(),x,y;
if(op&1)
{
x=read();y=read();swap(a[x],a[y]);
update(1,1,n,a[x],x);update(1,1,n,a[y],y);
}
else
{
res=mkp(-1,0);ans=1;query(1,1,n);
printf("%d\n",ans);
}
}
return 0;
}