用 \(\text{LCT}\) 维护边双的做法是:加入一条非树边时,将这段树上路径合并为一个点代表这个边双,具体实现用并查集合并点,在 \(\text{Splay}\) 与 \(\text{Access}\) 的过程中对辅助树上父亲做路径压缩。

用 \(\text{LCT}\) 维护点双的做法是:加入一条非树边时,将这段树上路径全部砍断,新建一个点代表这个点双,将原来那些点向新点连虚边。

实现方法:直接用 \(\text{Splay}\) 与 \(\text{Access}\) 提取路径并且 \(\text{DFS}\) 遍历这个路径就可以了。

代码是维护路径桥与割点的个数。 洛谷链接

#include<bits/stdc++.h>
using namespace std; const int N = 200005; int n,q,lst; struct bcj
{
int f[N];
void init()
{
for(int i=1; i<=n; i++)
f[i]=i;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
}G; namespace LCT
{
const int maxn = N;
int ch[maxn][2],fa[maxn],s[maxn],rev[maxn]; #define lc(x) (ch[x][0])
#define rc(x) (ch[x][1]) bcj W;
#define F(x) (W.find(x)) int g(int x)
{
return rc(fa[x]) == x;
} int nrt(int x)
{
return lc(fa[x]) == x || rc(fa[x]) == x;
} void pushup(int x)
{
s[x] = s[lc(x)] + s[rc(x)] + 1;
} void pushdown(int x)
{
if(rev[x])
{
swap(lc(lc(x)), rc(lc(x)));
rev[lc(x)] ^= 1;
swap(lc(rc(x)), rc(rc(x)));
rev[rc(x)] ^= 1;
rev[x] ^= 1;
}
} void rot(int x)
{
int y = fa[x], v = g(x);
if(nrt(y))
ch[fa[y]][g(y)] = x;
fa[x] = fa[y];
ch[y][v] = ch[x][!v];
fa[ch[x][!v]] = y;
ch[x][!v] = y;
fa[y] = x;
pushup(y);
} void splay(int x)
{
x = F(x);
int y; vector<int>v;
for(y = x; nrt(y); y = fa[y] = F(fa[y]))
v.push_back(y);
for(pushdown(y); !v.empty(); v.pop_back())
pushdown(v.back());
for(y = fa[x]; nrt(x); rot(x), y = fa[x] = F(fa[x]))
if(nrt(y))
rot(g(x) ^ g(y) ? x : y);
pushup(x);
} void access(int x)
{
x = F(x);
for(int y = 0; x; y = x, x = fa[x] = F(fa[x]))
{
splay(x);
rc(x) = y;
}
} void makeroot(int x)
{
x = F(x);
access(x);
splay(x);
swap(lc(x), rc(x));
rev[x] ^= 1;
} void link(int x, int y)
{
x = F(x); y = F(y);
makeroot(x);
access(y);
splay(y);
fa[x] = y;
} void dfs_merge(int x, int root)
{
W.f[x] = root;
if(lc(x)) dfs_merge(lc(x), root), lc(x) = 0;
if(rc(x)) dfs_merge(rc(x), root), rc(x) = 0;
} void zip(int x, int y)
{
x = F(x); y = F(y);
makeroot(x);
access(y);
splay(y);
dfs_merge(y, y);
pushup(y);
} int query(int x, int y)
{
x = F(x); y = F(y);
makeroot(x);
access(y);
splay(y);
return s[y] - 1;
} #undef lc
#undef rc
#undef F
} namespace RST
{
const int maxn = N << 1;
int cnt,ch[maxn][2],fa[maxn],s[maxn],rev[maxn]; #define lc(x) (ch[x][0])
#define rc(x) (ch[x][1]) int g(int x)
{
return rc(fa[x]) == x;
} int nrt(int x)
{
return lc(fa[x]) == x || rc(fa[x]) == x;
} void pushup(int x)
{
s[x] = s[lc(x)] + s[rc(x)] + (x <= n);
} void pushdown(int x)
{
if(rev[x])
{
swap(lc(lc(x)), rc(lc(x)));
rev[lc(x)] ^= 1;
swap(lc(rc(x)), rc(rc(x)));
rev[rc(x)] ^= 1;
rev[x] ^= 1;
}
} void rot(int x)
{
int y = fa[x], v = g(x);
if(nrt(y))
ch[fa[y]][g(y)] = x;
fa[x] = fa[y];
ch[y][v] = ch[x][!v];
fa[ch[x][!v]] = y;
ch[x][!v] = y;
fa[y] = x;
pushup(y);
} void splay(int x)
{
int y; vector<int>v;
for(y = x; nrt(y); y = fa[y])
v.push_back(y);
for(pushdown(y); !v.empty(); v.pop_back())
pushdown(v.back());
for(y = fa[x]; nrt(x); rot(x), y = fa[x])
if(nrt(y))
rot(g(x) ^ g(y) ? x : y);
pushup(x);
} void access(int x)
{
for(int y = 0; x; y = x, x = fa[x])
{
splay(x);
rc(x) = y;
}
} void makeroot(int x)
{
access(x);
splay(x);
swap(lc(x), rc(x));
rev[x] ^= 1;
} void link(int x, int y)
{
makeroot(x);
access(y);
splay(y);
fa[x] = y;
} void dfs_merge(int x, int root)
{
fa[x] = root;
if(lc(x)) dfs_merge(lc(x), root), lc(x) = 0;
if(rc(x)) dfs_merge(rc(x), root), rc(x) = 0;
pushup(x);
} void zip(int x, int y)
{
makeroot(x);
access(y);
splay(y);
dfs_merge(y, ++cnt);
pushup(cnt);
} int query(int x, int y)
{
makeroot(x);
access(y);
splay(y);
return s[y];
} #undef lc
#undef rc
} int main()
{
scanf("%d %d", &n, &q);
G.init();
LCT::W.init();
RST::cnt = n;
for(int i = 1, opt, x, y; i <= q; i ++)
{
scanf("%d %d %d", &opt, &x, &y);
x = x ^ lst; y = y ^ lst;
if(opt == 1)
{
if(G.find(x) ^ G.find(y))
LCT::link(x, y), RST::link(x, y), G.f[G.find(x)] = G.find(y);
else
LCT::zip(x, y), RST::zip(x, y);
}
if(opt == 2)
{
if(G.find(x) ^ G.find(y))
puts("-1");
else
printf("%d\n", lst = LCT::query(x, y));
}
if(opt == 3)
{
if(G.find(x) ^ G.find(y))
puts("-1");
else
printf("%d\n", lst = RST::query(x, y));
}
}
return 0;
}

LCT 维护边双 / 点双的模板的更多相关文章

  1. 关于双端队列 deque 模板 && 滑动窗口 (自出)

    嗯... deque 即为双端队列,是c++语言中STL库中提供的一个东西,其功能比队列更强大,可以从队列的头与尾进行操作... 但是它的操作与队列十分相似,详见代码1: 1 #include < ...

  2. bzoj2959: 长跑 LCT+并查集+边双联通

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2959 题解 调了半天,终于调完了. 显然题目要求是求出目前从 \(A\) 到 \(B\) 的可 ...

  3. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  4. 高可用Mysql架构_Mycat集群部署(HAProxy + 两台Mycat+Mysql双主双从)

    既然大家都知道了Mysql分布式在大型网站架构中的作用,在这里就不再阐述.本片博客文章是基于我曾经搭建过的一个Mysql集群基础上实现的,实现过双主热备.读写分离.分库分表. 博客链接:http:// ...

  5. windows2003服务器双线双IP双网卡设置方法

    双线双ip很好,网通用户访问网通线路,电信用户访问电信线路.但很多人会选用导入静态路由表,这个办法看似完美,其实问题很多. 1.电信用户如果被解析到网通的ip上,服务器根据路由表会返回电信线路,但用户 ...

  6. 【洛谷1501】[国家集训队] Tree II(LCT维护懒惰标记)

    点此看题面 大致题意: 有一棵初始边权全为\(1\)的树,四种操作:将两点间路径边权都加上一个数,删一条边.加一条新边,将两点间路径边权都加上一个数,询问两点间路径权值和. 序列版 这道题有一个序列版 ...

  7. 【洛谷3950】部落冲突(LCT维护连通性)

    点此看题面 大致题意: 给你一棵树,\(3\)种操作:连一条边,删一条边,询问两点是否联通. \(LCT\)维护连通性 有一道类似的题目:[BZOJ2049][SDOI2008] Cave 洞穴勘测. ...

  8. 【BZOJ2049】[SDOI2008] Cave 洞穴勘测(LCT维护连通性)

    点此看题面 大致题意: 有\(n\)个洞穴,\(3\)种操作:连一条边,删一条边,询问两点是否联通. \(LCT\)维护连通性 这道题应该是\(LCT\)动态维护连通性的一道模板题. 考虑将\(x\) ...

  9. Docker 部署 RocketMQ 双主双从模式( 版本v4.7.0)

    文章转载自:http://www.mydlq.club/article/96/ 系统环境: 系统版本:CentOS 7.8 RocketMQ 版本:4.7.0 Docker 版本:19.03.13 一 ...

随机推荐

  1. (转)数据索引BTree

    .B-tree 转自:http://blog.csdn.net/hbhhww/article/details/8206846 B-tree又叫平衡多路查找树.一棵m阶的B-tree (m叉树)的特性如 ...

  2. css+div上下左右自适应居中

    主要记录自己日常积累的布局相关的东西,持续更新中. 1.登录框上下左右自适应居中 以前想要把登录表单始终放置在页面的中间,花了不少心思,一直以来用的解决方法都是用js,感觉有点麻烦不是很好,于是在网上 ...

  3. vue mvvm原理与简单实现 -- 上篇

    Object.defineProperty介绍-- let obj = {}; Object.defineProperty(obj,'school',{ configurable : true, // ...

  4. 使用imread()函数读取图片的六种正确姿势

    OpenCV实践之路——使用imread()函数读取图片的六种正确姿势 opencv里的argv[1]指向的文件在哪里 测试 #include "opencv2/highgui/highgu ...

  5. LUT

    FPGA大多为LUT+寄存器的够,实现工艺为SRAM:寄存器很好理解,存储器的一种,用于存储指令和数据,多位于CPU内.拿什么是LUT呢? LUT:即Look up table,查找表,其本质是一个R ...

  6. mysql-sql逻辑查询顺序

    1.sql逻辑执行顺序(物理执行顺序可能会因索引而不同) SELECT  7  DISTINCT 8 FROM  1 JOIN     2 ON      3 WHERE  4 GROUP BY 5 ...

  7. lnmt

    目录 1.nginx安装与配置 1.1安装nginx 1.2nginx安装后的配置 2.mysql安装与配置 2.1安装mysql 2.2mysql配置 3.部署tomcat 3.1java环境安装 ...

  8. js bug

    1 加载模块脚本失败:服务器以非JavaScript MIME类型“text/html”响应. 描述:ES6 import Class时路径出错,少一个 / ,添上即可

  9. [lua]紫猫lua教程-命令宝典-L1-01-09. string字符串函数库

    L1[string]01. ASCII码互转 小知识:字符串处理的几个共同的几点 1.字符串处理函数 字符串索引可以为负数 表示从字符串末尾开始算起 所有字符串处理函数的 字符串索引参数都使用 2.所 ...

  10. 华为:向充电宝说再见!有它,手机24h不断电

    编辑 | 于斌 出品 | 于见(mpyujian) 虽然,美国与中国的谈判还在协商中,不知道最后的消息是好是坏. 但最近华为公司的成绩,却值得让我们为其喝彩和感到骄傲. 据悉,30日,华为在上半年业绩 ...