目录
题目链接:
A-Ancestor_"蔚来杯"2022牛客暑期多校训练营3 (nowcoder.com)
题目大意:
先给一组序列,再给a,b两个树,分别给两行,一行是n个树点的权值,一行是n-1个树点的父亲节点。要求:序列中去掉一个点后其余点在两树的公共祖先的权值进行比较,a大就ans++。求ans的大小。(即去掉点遍历)。
算法:
倍增算法,dfs。
想法:
预处理出关键点序列的在树A B上的前缀LCA和后缀LCA,枚举去掉的关键节点并使用前后缀LCA算出剩余节点的LCA比较权值。
但是朴素求祖先会超时,这时候就需要倍增算法。
倍增算法预处理:
void dfs(int x,int fath,int dep){
fa[x][0]=fath;
depth[x]=dep+1;
for (int i=1;(1<<i)<=dep+1;i++){
fa[x][i]=fa[fa[x][i-1]][i-1];//预处理x的第2^i个祖先
}
int len=v[x].size();
for (int i=0;i<len;i++){
if (v[x][i]!=fath){
dfs(v[x][i],x,dep+1);//常规dfs
}
}
}
倍增算法求公共祖先:
int LCA(int p,int q){//让pq深度变成相同一次倍增,pq一起动一次倍增
if (a.depth[p]<a.depth[q]) swap(p,q);
nep(i,29,0){//倒序使用倍增是精髓
if (a.depth[p]>=a.depth[q]+(1<<i))
p=fa[p][i];
}
if (p==q) return p;
nep(i,29,0){
if (fa[p][i]!=fa[q][i]){
p=fa[p][i];
q=fa[q][i];
}
}
return fa[p][0];
}
题解:
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int,int>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define nep(i,r,l) for (int i=r;i>=l;i--)
#define CIO std::ios::sync_with_stdio(false)
using namespace std;
const int N=2e5+5;
int x[N];
int lca[N],lda[N],lcb[N],ldb[N];
int fa[N][30],fb[N][30];
vector<int> v[N];
struct shu{
int val[N];
int pp[N];
int depth[N];
}a,b;
void dfs1(int x,int fath,int dep){
fa[x][0]=fath;
a.depth[x]=dep+1;
for (int i=1;(1<<i)<=dep+1;i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
}
int len=v[x].size();
for (int i=0;i<len;i++){
if (v[x][i]!=fath){
dfs1(v[x][i],x,dep+1);
}
}
}
void dfs2(int x,int fath,int dep){
fb[x][0]=fath;
b.depth[x]=dep+1;
for (int i=1;(1<<i)<=dep+1;i++){
fb[x][i]=fb[fb[x][i-1]][i-1];
}
int len=v[x].size();
for (int i=0;i<len;i++){
if (v[x][i]!=fath){
dfs2(v[x][i],x,dep+1);
}
}
}
int LCA(int p,int q){
if (a.depth[p]<a.depth[q]) swap(p,q);
nep(i,29,0){
if (a.depth[p]>=a.depth[q]+(1<<i))
p=fa[p][i];
}
if (p==q) return p;
nep(i,29,0){
if (fa[p][i]!=fa[q][i]){
p=fa[p][i];
q=fa[q][i];
}
}
return fa[p][0];
}
int LCB(int p,int q){
if (b.depth[p]<b.depth[q]) swap(p,q);
nep(i,29,0){
if (b.depth[p]>=b.depth[q]+(1<<i))
p=fb[p][i];
}
if (p==q) return p;
nep(i,29,0){
if (fb[p][i]!=fb[q][i]){
p=fb[p][i];
q=fb[q][i];
}
}
return fb[p][0];
}
void work(){
int n,k;
cin>>n>>k;
rep(i,1,k) cin>>x[i];
rep(i,1,n) cin>>a.val[i];
rep(i,2,n){
cin>>a.pp[i];
v[a.pp[i]].push_back(i);
}
dfs1(1,-1,-1);
lca[1]=x[1];
rep(i,2,k){
lca[i]=LCA(lca[i-1],x[i]);
}
lda[k]=x[k];
nep(i,k-1,1){
lda[i]=LCA(lda[i+1],x[i]);
}
rep(i,1,n){
v[i].clear();
}
rep(i,1,n) cin>>b.val[i];
rep(i,2,n){
cin>>b.pp[i];
v[b.pp[i]].push_back(i);
}
dfs2(1,-1,-1);
lcb[1]=x[1];
rep(i,2,k){
lcb[i]=LCB(lcb[i-1],x[i]);
}
ldb[k]=x[k];
nep(i,k-1,1){
ldb[i]=LCB(ldb[i+1],x[i]);
}
int ans=0;
if (a.val[lda[2]]>b.val[ldb[2]]){
ans++;
}
rep(i,2,k-1){
int aa=LCA(lca[i-1],lda[i+1]);
int bb=LCB(lcb[i-1],ldb[i+1]);
if (a.val[aa]>b.val[bb]){
ans++;
}
}
if (a.val[lca[k-1]]>b.val[lcb[k-1]]){
ans++;
}
cout<<ans<<endl;
}
signed main(){
CIO;
{
work();
}
return 0;
}