首页 > 其他分享 >倍增并查集

倍增并查集

时间:2023-09-14 15:33:05浏览次数:34  
标签:log val int 查集 区间 操作 倍增

假如说我们有 \(n\) 个元素,\(m\) 次操作。每次操作给定 \(x,y,z\),要求对于任意 \(0\le i\le z\),将 \(x+i\) 和 \(y+i\) 合并,求最后的并查集形态。数据范围是 \(10^5\) 级别的。

我们考虑将 \(z\) 二进制拆分,那么可以将 \(z\) 分解为 \(O(\log n)\) 个 \(2\) 的整数次幂之和,也就可以将区间划分为 \(O(\log n)\) 个长度为 \(2\) 的整数次幂的区间,分别操作。现在区间长度只有 \(O(\log n)\) 种,考虑对于每种长度维护一个并查集。具体地,假如操作是 \(x,y,2^k\),那么我们需要将第 \(k\) 个并查集中的 \(x\) 和 \(y\) 合并,表示从 \(x\) 和 \(y\) 开始的连续 \(2^k\) 个数对应相同。

操作完之后,我们再考虑从大至小将大区间的贡献下传到小区间。我们满足第 \(2^{k+1}\) 层下传完了过后 \(2^k\) 这层的并查集形态符合所有大于等于 \(2^k\) 的区间产生的影响。原来的形态是符合本层区间产生的影响,那么我们将 \([l,l+2^{k+1})\) 在并查集中的根 \(u\) 找出来,将 \([l,l+2^k)\) 与 \([u,u+2^k)\)、将 \((l+2^k,l+2^{k+1})\) 与 \((u+2^k,u+2^{k+1})\) 合并,即可满足条件。时间复杂度 \(O((n+m)\log n)\)。

code
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
inline int read() {
	int val=0;
	char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) val=(val<<3)+(val<<1)+c-'0',c=getchar();
	return val; 
}
int n,m,fa[21][N];
int get(int t,int x) {
    if (fa[t][x]==x) return x;
    return fa[t][x]=get(t,fa[t][x]);
}
inline void merge(int t,int x,int y) {
    fa[t][get(t,x)]=get(t,y);
    return;
}
int main() {
    n=read(),m=read();
    for (int i=1;i<=n;i++) {
        for (int j=0;j<=20;j++) fa[j][i]=i;
    }
    for (int i=1;i<=m;i++) {
        int l1=read(),r1=read(),l2=read(),r2=read();
        int len=r1-l1+1;
        int x=0;
        for (int j=20;j>=0;j--) {
            if (x+(1<<j)<=len) {
                merge(j,l1+x,l2+x);
                x+=(1<<j);
            }
        }
    }
    for (int i=20;i>=1;i--) {
        for (int j=1;j+(1<<i)-1<=n;j++) {
            int u=get(i,j);
            merge(i-1,j,u);
            merge(i-1,j+(1<<(i-1)),u+(1<<(i-1)));
        }
    }
    return 0;
}

标签:log,val,int,查集,区间,操作,倍增
From: https://www.cnblogs.com/tulipenoire/p/17702635.html

相关文章

  • C++算法进阶系列之倍增算法解决求幂运算
    1.引言学习倍增算法,先了解什么是倍增以及倍增算法的优势。如果面前有一堆石子,要求计算出石子的总数量。这是一个简单的数数问题,可以:一颗石子一颗石子的数。两颗石子两颗石子的数。三颗石子三颗石子的数。或者更多颗石子更多颗石子的数……在石子很多的情况下,每一次选择更......
  • poj 1182 食物链---带权值的并查集
    这题就一组数据,用while(scnaf(“%d%d”,&n,&m)!=EOF)..就wa了,我wa了数次,无语了。。带权值的并查集,d[]数组存的是每个点和根节点的关系,同类为d[i]=0; 根节点吃i点为d[i]=1; i点吃根节点为d[i]=2;自己画图感受一下吧!!#include<stdio.h>#include<string.h>#include<stdlib.h>in......
  • hdu-3926-Hand in Hand-并查集
    判断两个图是否同构。。用了并查集。。#include<stdio.h>#include<string.h>#include<stdlib.h>#include<algorithm>#include<queue>#include<stack>usingnamespacestd;#definelllonglongintn,m;structnode{ intfu; intsum; intf......
  • 【模板】最近公共祖先LCA——倍增
    题目来自洛谷P3379【模板】最近公共祖先(LCA)【模板】最近公共祖先(LCA)题目描述如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。输入格式第一行包含三个正整数\(N,M,S\),分别表示树的结点个数、询问的个数和树根结点的序号。接下来\(N-1\)行每行包含两个正整数......
  • 并查集 堆排序 (9/10)
    并查集模板 注意查找到后查找的节点直接连接根节点#include<iostream>usingnamespacestd;constintN=100010;intp[N];//关键记住find函数intfind(inta){if(p[a]!=a)p[a]=find(p[a]);//不等于根节点就往头结点走,并且等于returnp[a];}intma......
  • 倍增求lca
    步骤:1.前置准备:lg数组,depth数组,fa数组2.若x与y不在同一深度,先让它们跳到同一深度3.开始倍增往上跳代码:#include<iostream>#include<cstdio>usingnamespacestd;constlonglongN=1e6+10;intn,m,s,h1,h2,lg[N],fa[500010][30],depth[N];inttot=0,head[N],nxt[N],v[N......
  • IU86751低空载电流,40倍增益免滤波,2X28W双声道或50W音频放大器
    IU86751E是一款2x28W立体声;在单声道使用的情况下;最高可输出50W高效D类音频功率放大电路。先进的EMI抑制技术使得在输出端口采用廉价的铁氧体磁珠滤波器就可以满足EMC要求。IU86751E音频功率放大器是为需要输出高质量音频功率的系统设计的,它采用表面贴装技术,只需少量的外围器件,便使......
  • (测试)带权并查集
    带权并查集普通的并查集只能维护每个节点所在集合的编号,带权并查集则可以维护集合内任意一点到所在集合根的距离。带权并查集是结点存有权值信息的并查集。相比于一般的并查集,带权并查集需要开辟两个数组:一个是dsu[N],用来判断集合关系;一个是dis[N],用来描述其与根节点的关系。当......
  • [kuangbin带你飞]专题五 并查集
    WirelessNetwork POJ-2236 题意:n台电脑,坐标(x,y),电脑通讯范围为d;一开始,给出所有电脑坐标,然后所有电脑初始状态都是坏的,题目输入两个操作,第一修电脑且这台电脑可对d范围内正常电脑进行通讯了;第二就是查询,两台电脑是否可以通讯?算法:并查集思路:第一次,我直接通过坐标判断,那些电......
  • Cross Swapping CFE (并查集正负集合)
     思路:把每个草做抽象为点, 观察性质:图中对称的2个点,要交换,可以通过2种的操作方式得到, 2个操作异号, 反之2个操作同号通过+-表示和祖父是什么关系,通过并查集来看看当前有没有在同一个集合里面. ......