当前位置: 首页 > news >正文

牛客多校2 - Ancestor(LCA,前后缀)

https://ac.nowcoder.com/acm/contest/33188/A

题意
给定两棵树 A 和 B,分别有 n 个节点,每个节点分别有权值 a i a_i ai b i b_i bi
给定长度为 m 的数列 x 1 ,   x 2 ,   . . . ,   x m x_1,\ x_2,\ ...,\ x_m x1, x2, ..., xm,可以选择一个元素删掉。
问,有多少种方案能够满足,删掉后 剩余所有元素在A树上 LCA 的权值 大于 在B树上 LCA 的权值

2 ≤ m ≤ n ≤ 1 0 5 2≤m≤n≤10^5 2mn105

思路
这题考察了 LCA 的一个性质,与 求和,求gcd,求异或 … 都有的性质 —— 无序性,可结合性。

即,若干个数求 LCA,求和,求gcd,求异或等等都和运算顺序没有关系,并且如果已经算出若干个数的答案,现在加进来一个数,那么用算出的结果直接和该数运算即可。

那么这道题中,只删掉了一个数,那么其余数为这个数左边的数和右边的数,把左边所有数算出的 LCA 和右边所有数算出的 LCA 取 LCA 就是这剩下所有数的 LCA。

那么就可以提前预处理出前缀 LCA 和 后缀 LCA,然后 O(n) 遍历删除元素的位置即可。

Code
实现1:

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define fi first
#define se second
#define endl '\n'

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], b[N];
int x[N];
int pre1[N], pre2[N], Last1[N], Last2[N];
int dep[3][N], f[3][N][30], K;
vector<int> e[3][N];

void dfs(int k, int x, int fa)
{
	for(int tx : e[k][x])
	{
		if(tx == fa) continue;
		
		dep[k][tx] = dep[k][x] + 1;
		f[k][tx][0] = x;
		
		for(int i=1;i<=K;i++)
			f[k][tx][i] = f[k][f[k][tx][i-1]][i-1];
		
		dfs(k, tx, x);
	}
}

int lca(int k, int x, int y)
{
	if(dep[k][x] < dep[k][y]) swap(x, y);
	
	for(int i=K;i>=0;i--){
		if(dep[k][f[k][x][i]] >= dep[k][y]) x = f[k][x][i];
	}
	if(x == y) return x;
	
	for(int i=K;i>=0;i--){
		if(f[k][x][i] != f[k][y][i]) x = f[k][x][i], y = f[k][y][i];
	}
	return f[k][x][0];
}

signed main(){
	Ios;
	cin >> n >> m;
	K = log(n)/log(2);
	for(int i=1;i<=m;i++) cin >> x[i];
	
	for(int i=1;i<=n;i++) cin >> a[i];
	for(int i=2;i<=n;i++)
	{
		int t; cin >> t;
		e[1][i].push_back(t);
		e[1][t].push_back(i);
	}
	
	for(int i=1;i<=n;i++) cin >> b[i];
	for(int i=2;i<=n;i++)
	{
		int t; cin >> t;
		e[2][i].push_back(t);
		e[2][t].push_back(i);
	}
	
	dep[1][1] = dep[2][1] = 1;
	dfs(1, 1, 0);
	dfs(2, 1, 0);
	
	pre1[1] = x[1];
	for(int i=2;i<=m;i++)
		pre1[i] = lca(1, pre1[i-1], x[i]);
	Last1[m] = x[m];
	for(int i=m-1;i>=1;i--)
		Last1[i] = lca(1, Last1[i+1], x[i]);
	
	pre2[1] = x[1];
	for(int i=2;i<=m;i++)
		pre2[i] = lca(2, pre2[i-1], x[i]);
	Last2[m] = x[m];
	for(int i=m-1;i>=1;i--)
		Last2[i] = lca(2, Last2[i+1], x[i]);
	
	int cnt = 0;
	for(int i=1;i<=m;i++)
	{
		if(i == 1){
			if(a[Last1[2]] > b[Last2[2]]) cnt++;
		}
		else if(i == m){
			if(a[pre1[m-1]] > b[pre2[m-1]]) cnt++;
		}
		else if(a[lca(1, pre1[i-1], Last1[i+1])] > b[lca(2, pre2[i-1], Last2[i+1])]) cnt++;
	}
	cout << cnt;
	
	return 0;
}

实现2:

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define fi first
#define se second
#define endl '\n'

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], b[N];
int dep1[N], dep2[N], f1[N][30], f2[N][30], K;
int pre1[N], pre2[N], Last1[N], Last2[N];
int x[N];
vector<int> e1[N], e2[N];

void bfs1()
{
	dep1[1] = 1;
	queue<int> que;
	que.push(1);
	
	while(que.size())
	{
		int x = que.front(); que.pop();
		
		for(int tx : e1[x])
		{
			if(dep1[tx]) continue;
			dep1[tx] = dep1[x] + 1;
			que.push(tx);
			
			f1[tx][0] = x;
			for(int i=1;i<=K;i++)
				f1[tx][i] = f1[f1[tx][i-1]][i-1];
		}
	}
}

void bfs2()
{
	dep2[1] = 1;
	queue<int> que;
	que.push(1);
	
	while(que.size())
	{
		int x = que.front(); que.pop();
		
		for(int tx : e2[x])
		{
			if(dep2[tx]) continue;
			dep2[tx] = dep2[x] + 1;
			que.push(tx);
			
			f2[tx][0] = x;
			for(int i=1;i<=K;i++)
				f2[tx][i] = f2[f2[tx][i-1]][i-1];
		}
	}
}

int lca1(int x, int y)
{
	if(dep1[x] < dep1[y]) swap(x, y);
	
	for(int i=K;i>=0;i--)
		if(dep1[f1[x][i]] >= dep1[y]) x = f1[x][i];
	
	if(x == y) return x;
	
	for(int i=K;i>=0;i--)
		if(f1[x][i] != f1[y][i]) x = f1[x][i], y = f1[y][i];
		
	return f1[x][0];
}
int lca2(int x, int y)
{
	if(dep2[x] < dep2[y]) swap(x, y);
	
	for(int i=K;i>=0;i--)
		if(dep2[f2[x][i]] >= dep2[y]) x = f2[x][i];
	
	if(x == y) return x;
	
	for(int i=K;i>=0;i--)
		if(f2[x][i] != f2[y][i]) x = f2[x][i], y = f2[y][i];
		
	return f2[x][0];
}

signed main(){
	Ios;
	cin >> n >> m;
	K = log(n)/log(2);
	for(int i=1;i<=m;i++) cin >> x[i];
	
	for(int i=1;i<=n;i++) cin >> a[i];
	for(int i=2;i<=n;i++){
		int x; cin >> x;
		e1[i].push_back(x);
		e1[x].push_back(i);
	}
	for(int i=1;i<=n;i++) cin >> b[i];
	for(int i=2;i<=n;i++){
		int x; cin >> x;
		e2[i].push_back(x);
		e2[x].push_back(i);
	}
	
	bfs1();
	bfs2();
	
	pre1[1] = x[1], pre2[1] = x[1];
	for(int i=2;i<=m;i++)
		pre1[i] = lca1(pre1[i-1], x[i]), pre2[i] = lca2(pre2[i-1], x[i]);
	
	Last1[m] = x[m], Last2[m] = x[m];
	for(int i=m-1;i>=1;i--)
		Last1[i] = lca1(Last1[i+1], x[i]), Last2[i] = lca2(Last2[i+1], x[i]);
	
	int cnt = 0;
	for(int i=2;i<m;i++)
	{
		int l = i-1, r = i+1;
		int x = lca1(pre1[l], Last1[r]);
		int y = lca2(pre2[l], Last2[r]);
		if(a[x] > b[y]) cnt++;
	}
	if(a[Last1[2]] > b[Last2[2]]) cnt++;
	if(a[pre1[m-1]] > b[pre2[m-1]]) cnt++;
	
	cout << cnt;
	
	return 0;
}

经验
需要注意的一个细节,调了两个小时。。
求倍增的步数 2 k 2^k 2k 时,这个 k 为 l o g 2 n log_2n log2n,是 log(n)/log(2),不是单独的 log(n) !!

(精确这个 k 是为了减少往上跳的步数,也可以不精确,直接跳 30 步,复杂度高一些)

相关文章:

  • 【毕业设计】深度学习垃圾分类系统 - 机器视觉
  • Linux 编写shell脚本记录操作用户日志信息
  • 从零开始配置vim(19)——终端配置
  • 岑溪洁净实验室设计布局规划总结
  • 要不要做全链路压测
  • node.js云学堂微信小程序学习系统的设计与实现毕业设计源码011735
  • 前端知识3-JavaScript
  • 函数和二维数组
  • 马士兵老师JVM调优(修订版)
  • OpenCV使用教程-读取图像imread使用说明
  • 项目应用RabbitMQ简单配置
  • k8s Seata1.5.1
  • Linux 搭建nginx redis mysql rabbitmq以及配置SSL
  • 点击化学DBCO-PEG-FITC|二苯并环辛炔-聚乙二醇-异硫氰基荧光素
  • 离线数仓(8):ODS层实现之导入流量日志
  • Apache Spark Streaming 使用实例
  • flutter的key在widget list的作用以及必要性
  • JAVA SE 6 GC调优笔记
  • leetcode46 Permutation 排列组合
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • win10下安装mysql5.7
  • 反思总结然后整装待发
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 我有几个粽子,和一个故事
  • LIGO、Virgo第三轮探测告捷,同时探测到一对黑洞合并产生的引力波事件 ...
  • ​如何防止网络攻击?
  • !!Dom4j 学习笔记
  • #、%和$符号在OGNL表达式中经常出现
  • #微信小程序(布局、渲染层基础知识)
  • (007)XHTML文档之标题——h1~h6
  • (C语言)fgets与fputs函数详解
  • (ibm)Java 语言的 XPath API
  • (js)循环条件满足时终止循环
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (python)数据结构---字典
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (ros//EnvironmentVariables)ros环境变量
  • (ZT)出版业改革:该死的死,该生的生
  • (第27天)Oracle 数据泵转换分区表
  • (力扣题库)跳跃游戏II(c++)
  • (四) Graphivz 颜色选择
  • (太强大了) - Linux 性能监控、测试、优化工具
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET DataGridView数据绑定说明
  • .net 流——流的类型体系简单介绍
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .net和php怎么连接,php和apache之间如何连接
  • .NET下ASPX编程的几个小问题
  • /proc/stat文件详解(翻译)
  • @angular/cli项目构建--http(2)
  • [ linux ] linux 命令英文全称及解释
  • [4.9福建四校联考]
  • [8-23]知识梳理:文件系统、Bash基础特性、目录管理、文件管理、文本查看编辑处理...
  • [⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记
  • [AIR] NativeExtension在IOS下的开发实例 --- IOS项目的创建 (一)