题解
题目就是求树上路径的最大\(Mex\)
直接在树上维护这些东西难度有点大
但是\(Mex\)表示的是最小的没有出现过的自然数
这样我们就可以按照数为下标建立线段树
那么一个代表\([l,r]\)的线段树节点就代表了\([l,r]\)之间的这些数能否构成一条路径
注意:这里的能构成路径不是恰好能形成一条路径,而是不能确定一定不能形成一条路径
那么线段树的每个节点就还需要维护链的两个端点
然后合并信息的时候就是分类讨论
枚举两个端点,看剩下的两个点是否在这条路径上
就大致这么判断
return ((((LCA(x , u) == x) ^ (LCA(x , v) == x)) || LCA(u , v) == x) && (((LCA(y , u) == y) ^ (LCA(y , v) == y)) || LCA(u , v) == y)) ;
然后查询的时候就在线段树上二分
找到最晚的无法构成路径的数即为答案
代码
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 400005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n ;
int val[M] , fa[M] , pos[M] , lg[M * 2] ;
int cnt , stp[M] , edp[M] , dep[M] , st[M * 2][21] , ans ;
vector < int > vec[M] ;
inline void add_edge(int u , int v) {
vec[u].push_back(v) ;
}
inline int Mindep(int u , int v) { return dep[u] < dep[v] ? u : v ; }
inline int Maxdep(int u , int v) { return dep[u] > dep[v] ? u : v ; }
void dfs(int u , int father) {
stp[u] = edp[u] = ++ cnt ; dep[u] = dep[father] + 1 ; st[cnt][0] = u ;
for(int i = 0 , v ; i < vec[u].size() ; i ++) {
v = vec[u][i] ; if(v == father) continue ;
dfs(v , u) ; st[++cnt][0] = u ; edp[u] = cnt ;
}
}
inline int LCA(int x , int y) {
if(dep[x] > dep[y]) swap(x , y) ;
int l = stp[x] , r = edp[y] ;
if(l > r) swap(l , r) ;
int j = lg[r - l + 1] ;
return Mindep( st[l][j] , st[r - (1 << j) + 1][j] ) ;
}
inline bool On(int u , int v , int x , int y) {
return ((((LCA(x , u) == x) ^ (LCA(x , v) == x)) || LCA(u , v) == x) && (((LCA(y , u) == y) ^ (LCA(y , v) == y)) || LCA(u , v) == y)) ;
}
# define ls (now << 1)
# define rs (now << 1 | 1)
struct Node {
bool exist ;
int lp , rp ;
} t[M * 4] , tmp ;
inline Node Merge(Node p1 , Node p2) {
Node p ; p.lp = p.rp = -1 ; p.exist = false ;
int lp1 = p1.lp , rp1 = p1.rp , lp2 = p2.lp , rp2 = p2.rp ;
if(On(lp1 , rp1 , lp2 , rp2)) p.exist = true , p.lp = lp1 , p.rp = rp1 ;
else if(On(lp2 , rp2 , lp1 , rp1)) p.exist = true , p.lp = lp2 , p.rp = rp2 ;
else if(On(lp1 , lp2 , rp1 , rp2)) p.exist = true , p.lp = lp1 , p.rp = lp2 ;
else if(On(lp1 , rp2 , lp2 , rp1)) p.exist = true , p.lp = lp1 , p.rp = rp2 ;
else if(On(rp1 , lp2 , lp1 , rp2)) p.exist = true , p.lp = rp1 , p.rp = lp2 ;
else if(On(rp1 , rp2 , lp1 , lp2)) p.exist = true , p.lp = rp1 , p.rp = rp2 ;
return p ;
}
void build(int l , int r , int now) {
if(l == r) {
t[now].exist = true ;
t[now].lp = t[now].rp = pos[l] ;
return ;
}
int mid = (l + r) >> 1 ;
build(l , mid , ls) ;
build(mid + 1 , r , rs) ;
t[now] = Merge(t[ls] , t[rs]) ;
}
void Change(int x , int k , int l , int r , int now) {
if(l == r) {
t[now].lp = t[now].rp = k ;
t[now].exist = true ; return ;
}
int mid = (l + r) >> 1 ;
if(mid >= x) Change(x , k , l , mid , ls) ;
else Change(x , k , mid + 1 , r , rs) ;
t[now] = Merge(t[ls] , t[rs]) ;
}
void qry(int l , int r , int now) {
if(l == r) {
if( tmp.lp == -1 || Merge(tmp , t[now]).exist ) {
ans = max(ans , l) ;
if(tmp.lp != -1) tmp = Merge(tmp , t[now]) ;
else tmp = t[now] ;
}
return ;
}
int mid = (l + r) >> 1 ;
if(t[ls].exist && (tmp.lp == -1 || Merge(tmp , t[ls]).exist)) {
if(tmp.lp != -1) tmp = Merge(tmp , t[ls]) ;
else tmp = t[ls] ;
tmp.exist = true ;
ans = max(ans , mid) ;
qry(mid + 1 , r , rs) ;
}
else qry(l , mid , ls) ;
}
# undef ls
# undef rs
int main() {
n = read() ;
for(int i = 2 ; i <= n * 2 ; i ++)
lg[i] = lg[i >> 1] + 1 ;
for(int i = 1 ; i <= n ; i ++) {
val[i] = read() ;
pos[val[i]] = i ;
}
for(int i = 2 ; i <= n ; i ++) {
fa[i] = read() ;
add_edge(fa[i] , i) ;
}
dfs(1 , 1) ;
for(int j = 1 ; j <= lg[n * 2] ; j ++)
for(int i = 1 ; i + (1 << j) - 1 <= n * 2 ; i ++)
st[i][j] = Mindep( st[i][j - 1] , st[i + (1 << (j - 1))][j - 1] ) ;
build(0 , n - 1 , 1) ;
int Q = read() , opt , x , y ;
while(Q --) {
opt = read() ;
if(opt == 1) {
x = read() ; y = read() ;
Change(val[x] , pos[val[y]] , 0 , n - 1 , 1) ;
Change(val[y] , pos[val[x]] , 0 , n - 1 , 1) ;
swap(pos[val[x]] , pos[val[y]]) ;
swap(val[x] , val[y]) ;
}
else {
ans = 0 ;
tmp.lp = tmp.rp = -1 ;
tmp.exist = true ;
qry(0 , n - 1 , 1) ;
printf("%d\n",ans + 1) ;
}
}
return 0 ;
}
原文地址:https://www.cnblogs.com/beretty/p/10726029.html
时间: 2024-10-17 06:56:13