这题卡倍增害我T了一发= =
显然Mex是可以二分的,于是就可以考虑二分一个Mex然后check一下
然后怎么check呢?可以对点权建一棵线段树,节点\([l,r]\)表示,链上点权的集合包括\([l,r]\)时,最短的链的端点
合并两个区间就是在四个端点间选两个作为新链的端点,判断另外两个端点在不在这条链上,在的话这就是一条合法的链。判断方法就是判断一下两段的距离是否等于一整条链的距离。
这样时间复杂度是\(O(nlog^2n)\),感觉可过的样子?然而还可以在线段树上二分把时间复杂度优化到\(O(nlogn)\)
大概就是:如果\([l,r]\)区间合法,直接合并起来,否则往左扩展。如果左半边的区间全部都合并起来了就可以往右扩展。
下面就是代码实现啦
int query(int l,int r,int o,qwq &x){
if(t[o].u&&t[o].v){
if(!x.u){ x=t[o];return r; }//第一次合并
qwq tmp=x+t[o];
if(tmp.u){ x=tmp;return r; } //[l,r]区间合法
}
if(l==r){return (x+t[o]).u?l:0; }
int mid=l+r>>1;
int res=query(lson,x);
if(res<mid) return res;//不能向右合并
else return max(query(rson,x),res);//取max是考虑[1,mid]不能往后合并的情况
}
代码:
#include <bits/stdc++.h>
#define N 200005
#define bas 1,n,1
#define lson l,mid,(o<<1)
#define rson mid+1,r,(o<<1|1)
#define pb push_back
using namespace std;
int a[N],b[N],dep[N],cnt=0,top[N],sz[N],fa[N],son[N];
vector<int>g[N];
void dfs1(int x){
sz[x]=1,dep[x]=dep[fa[x]]+1;
for(int i=0;i<g[x].size();++i){
dfs1(g[x][i]);
sz[x]+=sz[g[x][i]];
if(sz[g[x][i]]>sz[son[x]]) son[x]=g[x][i];
}
}
void dfs2(int x,int s){
top[x]=s;
if(!son[x]) return;
dfs2(son[x],s);
for(int i=0;i<g[x].size();++i)
if(g[x][i]!=son[x]) dfs2(g[x][i],g[x][i]);
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int dis(int x,int y){ return dep[x]+dep[y]-2*dep[lca(x,y)]; }
bool pd(int x,int y,int z){ return dis(x,y)==dis(x,z)+dis(y,z); }
struct qwq{
int u,v;
qwq operator +(const qwq &a)const{
if(!u||!v||!a.u||!a.v) return (qwq){0,0};
if(pd(a.u,u,v) && pd(a.u,u,a.v)) return (qwq){a.u,u};
if(pd(a.u,v,u) && pd(a.u,v,a.v)) return (qwq){a.u,v};
if(pd(a.u,a.v,u) && pd(a.u,a.v,v)) return (qwq){a.u,a.v};
if(pd(u,a.v,a.u) && pd(u,a.v,v)) return (qwq){u,a.v};
if(pd(u,v,a.u) && pd(u,v,a.v)) return (qwq){u,v};
if(pd(a.v,v,a.u) && pd(a.v,v,u)) return (qwq){a.v,v};
return (qwq){0,0};
}
} t[N<<2],pmt;
void build(int l,int r,int o){
if(l==r){ t[o]=(qwq){b[l],b[l]};return; }
int mid=(l+r)>>1;t[o]=(qwq){0,0};
build(lson);
build(rson);
t[o]=t[o<<1]+t[o<<1|1];
}
void update(int l,int r,int o,int x){
if(l==r){ t[o]=(qwq){b[l],b[l]};return; }
int mid=(l+r)>>1;
if(x<=mid) update(lson,x);
else update(rson,x);
t[o]=t[o<<1]+t[o<<1|1];
}
int query(int l,int r,int o,qwq &x){
if(t[o].u&&t[o].v){
if(!x.u){ x=t[o];return r; }
qwq tmp=x+t[o];
if(tmp.u){ x=tmp;return r; }
}
if(l==r){return (x+t[o]).u?l:0; }
int mid=l+r>>1;
int res=query(lson,x);
if(res<mid) return res;
else return max(query(rson,x),res);
}
int main(){
int n,x,q,i,op,y;scanf("%d",&n);
for(i=1;i<=n;++i) scanf("%d",&a[i]),a[i]++,b[a[i]]=i;
for(i=2;i<=n;++i) scanf("%d",&fa[i]),g[fa[i]].pb(i);
dfs1(1),dfs2(1,1);
build(bas);
scanf("%d",&q);
while(q--){
scanf("%d",&op);
if(op==1){
scanf("%d%d",&x,&y);
swap(b[a[x]],b[a[y]]),swap(a[x],a[y]);
update(bas,a[x]),update(bas,a[y]);
} else pmt=(qwq){0,0},printf("%d\n",query(bas,pmt));
}
}
原文地址:https://www.cnblogs.com/PsychicBoom/p/10863665.html
时间: 2024-10-17 06:56:08