【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)

做过类似的题,原来有模板。

【记录】「SCOI2016」三道模拟赛/26.7.12-CSDN博客

这里面的第三道。


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

typedef long long LL;
const LL P = 998244353;
const int N = 5e5 + 10;

LL a[N], ans;
int fa[21][N];
// fa[i][j] 其实并不代表着 [j, j + (1 << i) - 1] 区间的都属于 j 的并查集
// 不然初始化的时候不就直接把区间合并了嘛!
// 其实这不能单独来看,换句话说,只有两个不同的 j
// 在 fa[i] 里都属于一个并查集,才能代表 [j, j + (1 << i) - 1] 和 [j', j' + (1 << i) - 1] 同属
// 这类似于懒标记,但不是向下传递
// 如果这一层两个不同的点并查集相同,那就没有接着往下的必要了 

int findfa(int c, int x) {
	if (fa[c][x] == x) {
		return fa[c][x];
	}
	return fa[c][x] = findfa(c, fa[c][x]);
}

void merge(int C, int x, int y) {
	int tx = findfa(C, x), ty = findfa(C, y);
	if (tx != ty) {
		fa[C][tx] = ty;   // 合并第 C 层的并查集 
		if (C != 0) {
			merge(C - 1, x, y);
			merge(C - 1, x + (1 << (C - 1)), y + (1 << (C - 1)));
		}
		else {
			ans = (ans + a[tx] * a[ty] % P) % P; 
			a[ty] = (a[ty] + a[tx]) % P;   
			 // 只有到最底层才合并 a 数组,因为 a 数组管的是单个 
		}
	}
}

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n, Q;
	cin >> n >> Q;
	
	for (int i = 0; i < n; i ++) {
		cin >> a[i];
	}
	
	for (int i = 0; i <= 20; i ++) {
		for (int j = 0; j < n; j ++) {
			fa[i][j] = j;
		}
	}
	
	ans = 0;
	while (Q --) {
		int len, x, y;
		cin >> len >> x >> y;
		if (len == 0) {
			cout << ans << "\n";
			continue;
		}
		
		int lg = log2(len);
		// 1<<(log2(n)) <= n
		// len = 0 时 lg 会等于负数,所以要特判 
		merge(lg, x, y);
		merge(lg, x + len - (1 << lg), y + len - (1 << lg));
		
		cout << ans << "\n";
	}
	
	return 0;
} 
相关推荐
chenbingjie_c6 分钟前
手撕 C++ priority_queue:二叉堆 + 模板仿函数 + 模板特化(保姆级逐函数拆解)
开发语言·c++
wang09079 分钟前
硬着头皮学数据结构和算法之Myers算法
数据结构·算法
蓝悦无人机21 分钟前
无人机系列之飞控算法:从PID到AI,飞行控制的核心进化
人工智能·算法·无人机·飞控系统
憨波个23 分钟前
【说话人日志】DiariZen
人工智能·深度学习·算法·语音识别
用户73416810354825 分钟前
被忽视的输入:为什么变工况故障诊断需要引入控制回路信号?
算法
小小龙学IT27 分钟前
C++ Redis 客户端深度解析(hiredis 与 redis-plus-plus)——工业数采实时缓存 C++ 侧实战
c++·redis·缓存
垆边人似月.37 分钟前
华为机试题 :最长递增子序列题目
数据结构·c++·算法·华为
动词ing1 小时前
【题目练习】算法 组合总和
算法
程序员-Benothing1 小时前
Linux文本排序统计命令:sort、uniq、wc、cut、tr实战
java·开发语言·算法
开发者联盟league1 小时前
c++11 使用chrono库转换时间点和字符串,计算时间点间隔
java·c++·算法