首页 > 其他分享 >"蔚来杯"2022牛客暑期多校训练营3 A. Ancestor(LCA)

"蔚来杯"2022牛客暑期多校训练营3 A. Ancestor(LCA)

时间:2022-11-16 11:15:05浏览次数:46  
标签:fa int 蔚来 LCA 多校 da 牛客 fb lca

题目大意是给定两棵节点数相同的树,每个点有一个权值。现在给出k个关键点编号,问有多少个关键点编号,将其删除后在两棵树上分别对剩下的关键点编号对应的点求LCA得到的两个祖先中第一棵树的祖先权值大于第二棵树的祖先权值。

首先可以扫一遍所有的关键点,如果这个点满足条件就更新答案。那么问题就转化成了删除一个点,怎么求剩下两边的点的LCA。注意到LCA计算满足交换律和结合律,因此可以维护每棵树对应关键点的前缀LCA(设为LCA_pre)和后缀LCA(设为LCA_suf),如果删去点i,那么剩下的点的LCA就是lca(LCA_pre[i - 1], LCA_suf[i + 1])。单独判断一下边界即可。

#include <bits/stdc++.h>
#define N 200005
using namespace std;
int n, k, x[N], a[N], b[N];
int heada[N], vera[2 * N], Nexta[2 * N], tota = 0;
int headb[N], verb[2 * N], Nextb[2 * N], totb = 0;
int lca_a1[N], lca_a2[N], lca_b1[N], lca_b2[N];
int fa[N][20], da[N];
queue<int> qa;
int fb[N][20], db[N];
queue<int> qb;
int t;
void adda(int x, int y) {
	vera[++tota] = y, Nexta[tota] = heada[x], heada[x] = tota;
}
void addb(int x, int y) {
	verb[++totb] = y, Nextb[totb] = headb[x], headb[x] = totb;
}
void bfsa() {
	qa.push(1); da[1] = 1;
	while(qa.size()) {
		int x = qa.front(); qa.pop();
		for(int i = heada[x]; i; i = Nexta[i]) {
			int y = vera[i];
			if(da[y]) continue;
			da[y] = da[x] + 1;
			fa[y][0] = x;
			for(int j = 1; j <= t; j++) {
				fa[y][j] = fa[fa[y][j - 1]][j - 1];
			}
			qa.push(y);
		}
	}
}	
void bfsb() {
	qb.push(1); db[1] = 1;
	while(qb.size()) {
		int x = qb.front(); qb.pop();
		for(int i = headb[x]; i; i = Nextb[i]) {
			int y = verb[i];
			if(db[y]) continue;
			db[y] = db[x] + 1;
			fb[y][0] = x;
			for(int j = 1; j <= t; j++) {
				fb[y][j] = fb[fb[y][j - 1]][j - 1];
			}
			qb.push(y);
		}
	}
}
int lca_a(int x, int y) {
	if(da[x] > da[y]) swap(x, y);
	for(int i = t; i >= 0; i--) {
		if(da[fa[y][i]] >= da[x]) y = fa[y][i];
	}
	if(x == y) return x;
	for(int i = t; i >= 0; i--) {
		if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	}
	return fa[x][0];
}
int lca_b(int x, int y) {
	if(db[x] > db[y]) swap(x, y);
	for(int i = t; i >= 0; i--) {
		if(db[fb[y][i]] >= db[x]) y = fb[y][i];
	}
	if(x == y) return x;
	for(int i = t; i >= 0; i--) {
		if(fb[x][i] != fb[y][i]) x = fb[x][i], y = fb[y][i];
	}
	return fb[x][0];
}
void solve() {
	cin >> n >> k;
	t = (int)(log(n) / log(2)) + 1;
	for(int i = 1; i <= k; i++) {
		cin >> x[i];
	}
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for(int i = 2; i <= n; i++) {
		int pa;
		cin >> pa;
		adda(pa, i);
		adda(i, pa);
	}
	for(int i = 1; i <= n; i++) {
		cin >> b[i];
	}
	for(int i = 2; i <= n; i++) {
		int pb;
		cin >> pb;
		addb(pb, i);
		addb(i, pb);
	}
	bfsa();
	bfsb();
	lca_a1[1] = x[1];
	for(int i = 2; i <= k; i++) {
		lca_a1[i] = lca_a(lca_a1[i - 1], x[i]);
	}
	lca_a2[k] = x[k];
	for(int i = k - 1; i >= 1; i--) {
		lca_a2[i] = lca_a(lca_a2[i + 1], x[i]);
	}
	lca_b1[1] = x[1];
	for(int i = 2; i <= k; i++) {
		lca_b1[i] = lca_b(lca_b1[i - 1], x[i]);
	}
	lca_b2[k] = x[k];
	for(int i = k - 1; i >= 1; i--) {
		lca_b2[i] = lca_b(lca_b2[i + 1], x[i]);
	}
	int ans = 0;
	for(int i = 1; i <= k; i++) {
		if(i == 1) {
			if(a[lca_a2[2]] > b[lca_b2[2]]) ans++;
		} else if(i == k) {
			if(a[lca_a1[k - 1]] > b[lca_b1[k - 1]]) ans++;
		} else {
			if(a[lca_a(lca_a1[i - 1], lca_a2[i + 1])] > b[lca_b(lca_b1[i - 1], lca_b2[i + 1])]) ans++;
		}
	}
	cout << ans << endl;
}

int main() {
	solve();
	return 0;
}

标签:fa,int,蔚来,LCA,多校,da,牛客,fb,lca
From: https://www.cnblogs.com/lipoicyclic/p/16895159.html

相关文章

  • 2022 年杭电多校第六场 Multiply 2 Divide 2
    2022年杭电多校第六场Multiply2Divide2题意:BXY的序列\(a\)长度为\(n\)\((1\leqn\leq10^5,1\leqa_i\leq10^5)\)对于每个操作,他选择一个数字\(a_i(1\leqi\leqn......
  • 牛客小白月赛60 E-寻找小竹!(数论)
    链接:https://ac.nowcoder.com/acm/contest/45670/E来源:牛客网题目大意:有n个城市,n-1条道路,每个城市都有它自己的优雅值ai而如果两个相邻的路口的优雅值存在至少两个共......
  • 牛客小白月赛60
    补一下题,c的状态方程都列出来了,但没想通d只剩几个样例没过没验出来,应该是连通性的问题,刚才换了个写法,都初始化成0x3f过了目录C.小竹关禁闭D游戏购买!C.......
  • 牛客小白月赛60 题解
    比赛通道:牛客小白月赛60前言第二次小白月赛没有AK,感觉自己可以原地退役了QAQ。这次F题理论上我能做出来,但是由于没有打表状态不佳,导致没有AK。A.小竹与妈妈思路这题......
  • 牛客小白月赛 54
    Asum把所有的数放进一个大根堆,然后每次取出最大的两个相加,累加到答案中去,并重新放回到大根堆。最大两数之和重新放入大根堆依旧是最大的数,所以可以优化成前缀和来做。#......
  • 牛客小白月赛55
    A至至子的等差中项#include<bits/stdc++.h>usingnamespacestd;int32_tmain(){inta,b;cin>>a>>b;cout<<b*2-a<<"\n";}B至至......
  • 牛客练习赛105
    切蛋糕的贝贝题意:将多边形一个蛋糕切成6份,使得面积之比为1:1:4:5:1:4(顺序可以打乱),只有两种切法,一种是将过外接圆的多边形的对角线,第二种是从多边形的中心和顶点的连线,先......
  • 牛客竞赛数学专题—整数分解与筛法
    题目链接A.青蛙的约会B.SumofConsecutivePrimeNumbersC.PrimeDistanceD. PrimeLandE. X-factorChainsA.青蛙的约会statement:两只......
  • 牛客java选择题每日打卡Day15
    牛客java选择题每日打卡Day15......
  • 牛客java选择题每日打卡Day7
    牛客java选择题每日打卡Day7......