动态图连通性(线段树分治+按秩合并并查集)
在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集。
题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图下所有联通块大小的乘积。
首先观察到如果没有撤销操作,那么直接用并查集就可以维护,每次合并的时候乘上要合并的两个并查集大小的逆元,然后乘上合并之后的大小即可。
那么来考虑撤销,观察到如果并查集不带路径压缩,应该是可以处理撤销操作的。
但我们并不能直接做,因为并查集的撤销必须按顺序来,就相当于每次合并的时候将一条边压入栈,撤销的时候也只能从栈顶弹出。如果不按顺序是维护不了的。
对于每个加边操作而言,我们将它和离它最近的那个撤销操作匹配(默认第m + 1个时刻有一个撤销所有边的操作)
假设加边操作出现在第l个时刻,撤销操作在第r个时刻,那么对于这个二元组而言,它的作用是使得加入的那条边在[l, r-1]的时间内出现。
于是我们考虑用线段树来处理这个东西,我们可以将这条边挂在线段树上,相当于在线段树上区间修改,将这条边挂在[l, r -1]的区间上,
因此每条边都会被拆分成log个区间,分别挂在线段树上的对应位置,然后当我们经过线段树上的一个节点时,我们就将这个节点上挂的边都加入到当前图中,相当于我们遍历了整个线段树,
线段树上的每个叶子节点都是一个询问(一个时刻),因此当我们遍历到一个叶子节点时,我们就会拥有当前时刻应该拥有的边。
当我们离开一个点时,我们就将在这个点上加入的边撤销,因为我们加边是从上往下遍历时一个一个加,而撤销是回溯时一个一个撤销,所以撤销是按顺序撤销的,所以并查集就可以维护了。
感觉讲的有一点混乱。。。。。
大概是一个区间上挂了一条边表示这条边在[l, r]中的所有时刻都出现了,当处理一个单点的时候,需要将到达这个单点的路径上经过的所有区间中的边都加入图中,撤销时按顺序撤销。
可能需要画个图之类的,应该还是比较好理解的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 101000 5 #define ac 500000 6 #define maxn 2010000 7 #define p 1000000007 8 #define LL long long 9 10 int n, m, top, cnt, w; 11 LL rnt = 1; 12 int Head[maxn], Next[maxn], date[maxn], tot; 13 int father[AC], up[AC]; 14 LL inv[AC], Size[AC], ans[AC]; 15 struct line{ 16 int x, y; 17 friend bool operator < (line a, line b) 18 { 19 if(a.x != b.x) return a.x < b.x; 20 else return a.y < b.y; 21 } 22 }road[AC]; 23 24 struct node{ 25 int fa, x; 26 }s[AC]; 27 28 map<line, int> MAP; 29 30 inline int read() 31 { 32 int x = 0;char c = getchar(); 33 while(c > '9' || c < '0') c = getchar(); 34 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 35 return x; 36 } 37 38 inline void add(int f, int w){ 39 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot; 40 } 41 42 inline int find(int x){ 43 while(father[x] != x) x = father[x]; 44 return x; 45 } 46 47 inline void link(int &ret, int x, int y) 48 { 49 int fx = find(x), fy = find(y); 50 if(fx == fy) return ; 51 ++ ret;//只有连接了才要加ret 52 if(Size[fx] > Size[fy]) swap(fx, fy); 53 rnt = rnt * inv[Size[fx]] % p * inv[Size[fy]] % p; 54 father[fx] = fy, Size[fy] += Size[fx]; 55 s[++top] = (node){fy, fx}; 56 rnt = rnt * Size[fy] % p; 57 } 58 59 inline void cut() 60 { 61 node x = s[top --];//撤销 62 rnt = rnt * inv[Size[x.fa]] % p; 63 father[x.x] = x.x, Size[x.fa] -= Size[x.x];//断开连接 64 rnt = rnt * Size[x.fa] % p * Size[x.x] % p;//注意删除一个点之后要把父亲修改为自己,而不是0 65 } 66 67 void solve(int x, int l, int r)//当前区间编号,区间范围 68 { 69 int now, ret = 0; 70 for(R i = Head[x]; i ; i = Next[i]) 71 { 72 now = date[i]; 73 link(ret, road[now].x, road[now].y); 74 } 75 int mid = (l + r) >> 1; 76 if(l == r) ans[l] = rnt; 77 if(l != r) solve(x * 2, l, mid), solve(x * 2 + 1, mid + 1, r); 78 for(R i = 1; i <= ret; i ++) cut(); 79 } 80 81 void pre() 82 { 83 n = read(), m = read(); 84 inv[0] = inv[1] = 1; 85 for(R i = 1; i <= n; i ++) father[i] = i, Size[i] = 1; 86 for(R i = 2; i <= n; i ++) 87 inv[i] = (p - p / i) * inv[p % i] % p; 88 } 89 90 void change(int x, int l, int r, int ll, int rr) 91 { 92 if(l == ll && r == rr){add(x, w); return ;} 93 int mid = (l + r) >> 1; 94 if(rr <= mid) change(x * 2, l, mid, ll, rr); 95 else if(ll > mid) change(x * 2 + 1, mid + 1, r, ll, rr); 96 else change(x * 2, l, mid, ll, mid), change(x * 2 + 1, mid + 1, r, mid + 1, rr); 97 } 98 99 void work() 100 { 101 int tmp; 102 for(R i = 1; i <= m; i ++) 103 { 104 int opt = read(), a = read(), b = read(); 105 if(a > b) swap(a, b); 106 if(!MAP[(line){a, b}]) 107 MAP[(line){a, b}] = ++ cnt, tmp = cnt, road[cnt] = (line){a, b}; 108 else tmp = MAP[(line){a, b}];//获取编号 109 if(opt == 1) up[tmp] = i;//存下这条边的出现时间 110 else w = tmp, change(1, 1, m, up[tmp], i - 1), up[tmp] = 0; 111 } 112 for(R i = 1; i <= cnt; i ++) 113 if(up[i]) w = i, change(1, 1, m, up[i], m); 114 solve(1, 1, m); 115 for(R i = 1; i <= m; i ++) printf("%lld\n", ans[i]); 116 } 117 118 int main() 119 { 120 //freopen("in.in", "r", stdin); 121 pre(); 122 work(); 123 //fclose(stdin); 124 return 0; 125 }
View Code
转载于:https://www.cnblogs.com/ww3113306/p/9896276.html
动态图连通性(线段树分治+按秩合并并查集)相关推荐
- 20211229[按秩合并并查集 最小生成树][BZOJ4668]冷战
20211229[按秩合并并查集.最小生成树][BZOJ4668]冷战 题意:给定N点,动态加边与询问两点最早是哪条边开始连通,强制在线 首先如果离线的话可以直接跑最小生成树,不过代码不好处理. 当然 ...
- BZOJ 4668 冷战(按秩合并并查集+LCA)
4668: 冷战 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 627 Solved: 303 [Submit][Status][Discuss] ...
- CCPC-Wannafly Winter Camp Day3 (Div2, onsite) I 石头剪刀布(按秩合并并查集)
题解:每次有两个事件: y y去挑战xx,如果赢了可以坐在x x的位置,打平或者输了就要被淘汰. 询问在进行所有一类事件后,有多少种情况可以让x x现在还没有被淘汰. 对于第二类事件,我们假设x x挑 ...
- 线段树分治 ---- CF1217F - Forced Online Queries Problem(假离线 可撤销并查集 + 线段树分治)详解
题目链接 题目大意 解题思路: 我一开始想到可以用可撤销并查集去维护这种删边加边的操作,但是有个缺点是每次撤销都有把后面的边全部撤销复度是O(n2)O(n^2)O(n2) 首先我们考虑这种动态加边删边 ...
- LOJ 121 「离线可过」动态图连通性——LCT维护删除时间最大生成树 / 线段树分治...
题目:https://loj.ac/problem/121 离线,LCT维护删除时间最大生成树即可.注意没有被删的边的删除时间是 m+1 . 回收删掉的边的节点的话,空间就可以只开 n*2 了. #i ...
- 牛客多校8 - All-Star Game(线段树分治+并查集按秩合并的撤销操作)
题目链接:点击查看 题目大意:有 n 个球员和 m 个球迷,一个球员可能是多个球迷的粉丝,需要选择最少的球员进行比赛,使得所有的球迷都愿意观看(对于每个球迷来说,都有至少一个其喜欢的球员入选比赛) 对 ...
- 【BZOJ4025】二分图(可撤销并查集+线段树分治)
题目: BZOJ4025 分析: 定理:一个图是二分图的充要条件是不存在奇环. 先考虑一个弱化的问题:保证所有边出现的时间段不会交叉,只会包含或相离. 还是不会?再考虑一个更弱化的问题:边只会出现不会 ...
- 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横
不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...
- CF938G Shortest Path Queries(线性基/线段树分治/异或)
CF938G Shortest Path Queries 支持加边删边和查询两点之间的异或最短路,我们可以使用线段树分治,然后利用线性基求解. 但是这里图可能不是联通的,所以查询两点之间的异或和需要边 ...
最新文章
- 如何设计日志采集系统?不妨看看这篇文章
- Google的深度学习强在哪?谷歌首席科学家说了这些奇妙特性
- Django搭建简易博客教程(四)-Models
- Metasploit渗透某高校域服务器
- 我的醉驾拘留15日记----第二日凌晨 午夜惊梦
- sql 分组求和_数据仓库工具–Hive(归纳笔记第六部分:SQL练习)
- 微软发动图明示新一代操作系统Windows 11
- CEH v8~v11 Module Slides 和 Lab Manual 下载
- 【算法】剑指 Offer 04. 二维数组中的查找 【重刷】
- 项目管理十大知识领域之间的关系
- 解决Untracked Files Prevent Checkout问题
- MTK移植大全(参考)建议收藏!
- vscode远端编程 终极方案
- ALCOA+CCEA原则(数据完整性标准)
- Android进阶之路 - StringUtils、NumberUtils 场景源码
- FlexRay总线的基本注意事项1——总线拓扑
- 根据物理公式在Unity中实现抛物线运动.1
- gulp之ES6转ES5
- [Vue]实现交换布局,输入关键词过滤列表内容
- 二、Oracle数据库的创建—通用
热门文章
- 疑惑?人工智能兴起为什么带火了Python,看完这篇你就明白了
- 【TensorFlow】TensorFlow从浅入深系列之四 -- 教你深入理解过拟合问题(正则化)
- 部编版是什么版本_教材部编版和人教版的区别
- 信安精品课:第3章密码学基本理论精讲笔记
- java mail 554_554邮件被拒绝:电子邮件地址未经验证[重复]
- vue中axios设置表单头_VUE项目axios请求头更改Content-Type操作
- 多线程和线程池的基本知识总结
- Dubbo标签在xml配置文件中报错的解决方法
- github优秀前端项目分享(转)
- 关于“只有静态常量整型数据成员才可以在类中初始化”