201905/16 膜你赛 关联点

本文介绍了一种算法,用于计算二叉树中每个节点的左关联点和右关联点数量。左关联点是在节点左子树中,距离为特定值的点;右关联点则在右子树中。通过倍增技巧,该算法能有效解决大规模数据集问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
【问题描述】
二叉树是一种常用的数据结构,一个二叉树或者为空,或者由根节点、左子树、右子树
构成,其中左子树和右子树都是二叉树. 每个节点 a 可以存储一个值 va.
显然,如果一个点 a 的左子树或右子树内有一个点 b,那么存在唯一的路径从 a 出发,
每次往左子树或右子树走,经过一系列节点访问到 b. 我们把从 a 到 b 经过除 a 以外的节
点数称为节点 a 到节点 b 的距离.
例如对于下图的二叉树, 1 为根节点, 51 的子树内,从 15 存在唯一的路径:
1 ! 2 ! 5,经过的除 1 外的节点有 2 个: 2; 5,因此节点 1 到节点 5 的距离为 2.
对于一个点 a,定义:
·若点 b 在 a 的左子树中,且 a 到 b 的距离为 vb,则称 b 为 a 的左关联点;
·若点 b 在 a 的右子树中,且 a 到 b 的距离为 vb,则称 b 为 a 的右关联点.
给定一个共有 n 个节点的二叉树,所有节点编号为 1; 2; :::; n,其中 1 为根节点. 给出
每个节点 a 存储的值 va,请输出每个节点的左关联点个数和右关联点个数.
【输入格式】
输入文件名为 node.in
第一行一个正整数 n,表示二叉树的总节点数.
第二行 n 个由空格分隔的正整数 v1; v2; :::; vn,第 i 个数 vi 表示节点 i 存储的值.
接下来 n 行,第 i 行为两个由空格分隔的整数,分别表示编号为 i 的左子树的根节点
(若左子树为空则为 0)和右子树的根节点(若右子树为空则为 0.
【输出格式】
输出文件名为 node.out
输出 n 行,第 i 行为两个整数,分别表示点 i 的左关联点个数和右关联点个数.
【样例输入】
5
2 1 3 2 1
2 3
4 5
0 0
0 0
0 0
【样例输出】
2 0
0 1
0 0
0 0
0 0
【样例说明】
节点 1 的左关联点有 2 个: 24,没有右关联点.
节点 2 没有左关联点,右关联点有 1 个: 5.
除此之外,其它节点没有关联点.
【数据规模与约定】
对于 30% 的数据, n ≤ 3.
对于 60% 的数据, n ≤ 500.
对于 100% 的数据, n ≤ 2000001 ≤ vi ≤ 200000,根节点 1 到任意节点的距离不超
过 100000.
思路:

很明显一倍增。

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

#define maxn 50000000
#define ll long long
#define read(x) scanf("%lld",&x)
#define md 1000000007
#define lowbit(x) x&-x;

ll n,m,a,b,c;
bool f[maxn+5];

int main() {
	read(n),read(m),read(a),read(b),read(c);
	
	ll x=0,ans1=0,ans2=0,cnt1=0,cnt2=0;
	for(int i=1;i<=m;i++) {
		x=(a*x+b)%(2*c*n);
		int id;
		if(x<n*c) {
			id=x/c+1;
			if(!f[id]) {
				f[id]=true;cnt1++,cnt2+=id;
			}
		} else {
			id=x/c-n+1;
			if(f[id]) {
				f[id]=false;cnt1--,cnt2-=id;
			}
		}
		ans1=(ans1+cnt1)%md,ans2=(ans2+cnt2)%md;
	}
	
	printf("%d %d",ans1,ans2);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值