用 \(\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. C++——简单程序设计

    1.一个简单的程序 #include <iostream> //iostream是头文件,用来说明要使用的对象的相关信息. using namespace std; //使用命名空间,解决 ...

  2. Android 验证APK签名对比

    最近OTT制定产品,其中有一条需求是只能安装自己公司签名的APK,所以在网上找了相关资料,最后总结功能实现如下: 1.签名错误码frameworks/base/core/java/android/co ...

  3. Unity中常用的数据结构总结

    本篇博文对U3D经常用到的数据结构和各种数据结构的应用场景总结下. 1.几种常见的数据结构 这里主要总结下在工作中常碰到的几种数据结构:Array,ArrayList,List<T>,Li ...

  4. Charles 查看https请求数据 Mac/ android

    Charles_v4.0.1_Mac_破解版下载地址:https://pan.baidu.com/s/1c23VPuS 1.在Mac电脑上安装Charles的根证书 打开Charles->菜单H ...

  5. Having用法以及其和Where区别

    例如,进行分组语句: select year,count(id) num from tblPlantProduce group by year 在这条语句中若要筛选出年份>2005年的有两种方式 ...

  6. dfs题型二(迷宫问题)

    取自:<王道论坛计算机考研机试指南>6.5节 例 6.7 Temple of the bone(九度 OJ 1461)时间限制:1 秒 内存限制:32 兆 特殊判题:否题目描述:The d ...

  7. 怎么把VS里的scanf_s换成scanf

    转自:https://blog.csdn.net/hansionz/article/details/79889039 方法一:在项目属性中---->配置属性------>C\C++---- ...

  8. goahead 流程

    原文:https://blog.csdn.net/qq_32419007/article/details/80756643 1.全局变量 Web服务器的根目录 static char_t        ...

  9. 初学Java时使用记事本开发出现的中文乱码问题

    如果是使用微软记事本,那就会麻烦一点,将后缀改为.txt,用记事本打开,左上方:文件→另存为→弹出的窗口的下方会出现使用的编码形式,将编码形式修改为ANSI编码,点击保存→确定替换即可,修改后将后缀改 ...

  10. css transform 2D3D转换

    2D转换 translate 移动 <style> div{ width: 100px; height: 100px; } .box{ border: 1px dashed red; fl ...