首页 > 其他分享 >哈希

哈希

时间:2024-08-30 16:47:44浏览次数:3  
标签:mid long 查询 修改 tag 哈希 区间

树状数组是个好东西,写起来也相对好看。但是操作比较局限,区间修改就掉回\(O(nlogn)\), 那还不如 \(O(n)\)。线段树完美的解决问题。

线段树,也可以理解的一堆线段组成的树。

大致如上,有一线段 \([l, r]\) 当 \(l \ne r\) 可化为 \([l, mid]\) , \([mid + 1, r]\)

PS: \(mid = (l + r) / 2\)

增加

此操作 不是 新加节点,是将一段区间增加一个数。

将 [2, 9] 每个数增加 1

像这样通过递归的方式修改这些节点,然后我们惊喜的发现,访问了 \(n logn\) 个节点......似乎不如没有

这个时候lazy_tag登场(懒人tag)

蓝色的就是lazy_tag(下文称为tag),标记增加了多少, 这时 \([2,2], [3,3],[4,5], [6,8], [9,9]\) 都有 tag = 1。

用处放到下文

查询

这里,我们可以查询区间的和

在上例子里我们查询 [1, 1]时,不会有问题,查询 [1, 2]时,不会有问题, 查询 [1, 10]时,不会有问题, 但是查询 [6, ]7时,有问题, 因为没有修改到。

因为 [6, 8] 被标有tag, 然而,在访问 [6, 7]时一定会访问到6, 8,那么我们便可以将tag传下来。

也就是不访问就不修改。

运用以上方案,就可以实现单点修改,单点查询,区间修改(同增同减), 区间查询。

#include<iostream>

using namespace std;

const long long kMaxN = 1e5 + 5; 

long long n, m, a[kMaxN << 2]; //注意开大4倍

struct L {
	long long sum, tag;
} sgt[kMaxN << 2];

void push_up(long long rt) { //更新这个节点
	sgt[rt].sum = sgt[rt << 1].sum + sgt[rt << 1 | 1].sum;
}	


void build_tree(long long rt, long long l, long long r) { //建树
	sgt[rt].tag=0;
	if (l == r) {
		sgt[rt].sum = a[l];
		return;
	}
	long long mid = l + r >> 1; 
	build_tree(rt << 1, l, mid), build_tree(rt << 1 | 1, mid + 1, r);
	push_up(rt);
}

void add_tag(long long rt, long long l, long long r,long long d) {//建立tag
	sgt[rt].tag += d;
	sgt[rt].sum += d * (r - l + 1);//值也增加
}

void push_down(long long rt, long long l, long long r) { //tag往下传
	if (sgt[rt].tag) {
		long long mid = l + r >> 1;
		add_tag(rt << 1, l, mid, sgt[rt].tag);
		add_tag(rt << 1 | 1, mid + 1, r, sgt[rt].tag);
		sgt[rt].tag = 0;
	}
}

void update(long long L, long long R, long long rt, long long l, long long r, long long d){ //更新[l, r]的值 + d
	if (L <= l && r <= R) {
		add_tag(rt, l, r, d);
		return;
	}
	push_down(rt, l, r);
	long long mid = l + r >> 1;
	if (L <= mid) {
		update(L, R, rt << 1, l, mid, d);
	} if (mid < R) {
		update(L, R, rt << 1 | 1, mid + 1, r, d);
	}
	push_up(rt);
} 

long long query(long long L, long long R, long long rt, long long l, long long r) {//找到 [L, R] 的和
	if (L <= l && r <= R) {
		return sgt[rt].sum;
	}
	push_down(rt, l, r);
	long long mid = l + r >> 1, ans = 0;
	if (L <= mid) {
		ans += query(L, R, rt << 1, l, mid);
	} 
	if (mid < R) {
		ans += query(L, R, rt << 1 | 1, mid + 1, r);
	}
	return ans;
}

int main(){
	cin >> n >> m;
	for (long long i = 1; i <= n; i++) {
		cin >> a[i];
	}
	build_tree(1, 1, n);
	for(long long i = 1, a, x, y, d; i <= m; i++) {
		cin >> a >> x >> y;
		if (a == 1) {
			cin >> d;
			update(x, y, 1, 1, n, d);
		} else {
			cout << query(x, y, 1, 1, n) << '\n';
		}
	}
	return 0;
} 

标签:mid,long,查询,修改,tag,哈希,区间
From: https://www.cnblogs.com/JiCanDuck/p/18389045

相关文章

  • Python——集合基本操作以及哈希函数
    Python中的集合(Set)是一个无序的、不包含重复元素的数据结构。集合主要用于数学上的集合操作,如并集、交集、差集和对称差集等。集合使用大括号 {} 来表示,但注意空集合不能使用 {} 表示(这会创建一个空字典),而应该使用 set() 来创建。创建集合1.使用大括号 {}:这是最直接......
  • 哈希表(及简单实现)
    1、什么是哈希表(散列表)要说哈希表,我们必须先了解一种新的存储方式—散列技术。散列技术是指在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每一个关键字都对应一个存储位置。即:存储位置=f(关键字)。这样,在查找的过程中,只需要通过这个对应关系f找到......
  • 哈希-快乐数
     解决这个问题的关键在于,判断结束遍历的条件,即当n!=1或者在循环过程中,没有出现过重复的数。 classSolution:defisHappy(self,n:int)->bool:defget_score(n):sum_=0whilen>0:end_=n%10......
  • 代码随想录 -- 哈希表 -- 四数之和
    18.四数之和-力扣(LeetCode)思路:(与三数之和类似,在外面加一层循环)    1. 先将nums 按升序排序    2. 初始状态:k=0,i= k+1,left= i+1,right= len(nums)-1        3. 进入第一层for循环:        如果 nums[k]>0andtarget>0 ......
  • 算法与数据结构——哈希算法
    哈希算法前面介绍了哈希表的工作原理和哈希冲突的处理方法。然而无论是开放寻址还是链式地址,它们只能保证可以在发生冲突时正常工作,而无法减少哈希冲突的发生。如果哈希冲突过于频繁,哈希表的性能则会急剧劣化。如下图所示,对于链式哈希表,理想情况下键值对均匀分布在各个桶中,达到......
  • 字符串哈希 详解+例题
    字符串哈希观看讲解视频:董晓算法做的笔记理论部分字符串哈希是把不同的字符串映射成不同的整数。对于一个长度为\(n\)的字符串\(s\),我们定义它的Hash函数为:\(h(s)=\Sigma^n_{i=1}\)\(s[i]\timesp^{n-i}\)\((mod\)\(m)\)例如:字符串\(abc\),他的hash函数值......
  • 算法与数据结构——哈希表
    哈希表哈希表(hashtable),又称散列表,它通过建立键key与值value之间的映射,实现高效的元素查询。具体而言,我们向哈希表中输入一个键key,则可以在O(1)时间内获取对应的值value。除哈希表外,数组和链表也可以实现查询功能,他们的效率对比如下表:添加元素:仅需将元素添加至数组(链表)的尾部......
  • 用哈希表求解力扣第217题 存在重复元素
    前言记录一下刷题历程力扣第217题存在重复元素两数之和原题目:给你一个整数数组nums。如果任一值在数组中出现至少两次,返回true;如果数组中每个元素互不相同,返回false。示例1:输入:nums=[1,2,3,1]输出:true示例2:输入:nums=[1,2,3,4]输出:false示例3:输......
  • 【Leetcode 2032 】 至少在两个数组中出现的值 —— 哈希表与按位运算符(最全的注解)
    给你三个整数数组 nums1、nums2 和 nums3 ,请你构造并返回一个 元素各不相同的 数组,且由 至少 在 两个 数组中出现的所有值组成。数组中的元素可以按 任意 顺序排列。示例1:输入:nums1=[1,1,3,2],nums2=[2,3],nums3=[3]输出:[3,2]解释:至少在两个数组中出......
  • LeetCode 690. 员工的重要性(哈希表、深度优先搜索dfs)
    题目:690.员工的重要性思路:先用哈希表map将每个员工的信息映射到员工ID对应的下标位置。接着使用深度优先搜索dfs,来记录总和即可。细节看注释/*//DefinitionforEmployee.classEmployee{public:intid;intimportance;vector<int>subordinates;......