【题解】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;
} 
相关推荐
神仙别闹8 小时前
基于 C++ 实现(控制台)学生成绩管理系统
开发语言·c++
会周易的程序员9 小时前
5 节点边缘冗余方案(上):基于 aiRaft 的物联网高可用控制面设计
c++·分布式·物联网·raft·iot·共识
有点。9 小时前
C++03阶段练习(练习题)
数据结构·算法·图论
周末也要写八哥10 小时前
经典算法实例:游戏中弱角色的数量(二)
算法
是Yu欸11 小时前
鸿蒙PC移植:2048 从网页小游戏到 AI 桌面应用
大数据·人工智能·算法·数据挖掘·openharmony·codex
鹿角片ljp11 小时前
KV Cache 解析
java·算法
liliangcsdn11 小时前
IVOL与偏度因子的对比测量分析
算法
qq_1998868712 小时前
第6板块·第4节:构建系统与多文件项目
c++·人工智能·gpu算力
threerocks12 小时前
Jev 入门第一课
算法
汉克老师13 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程