Solution

实际上就是查询 $u$ 到 $v$ 路径上 边双的个数 $ -1$。

并且题目仅有删边, 那么就离线倒序添边。

维护 边双 略有不同:

首先需要一个并查集, 记录 边双内的点。 在 添加边$(u,v)$时 , 若$u, v$ 已经相连, 那么把 $u, v$ 路径上的点 缩成一个点, 用最上面的点 来代替。

 void del(int x, int y) {
if (!x) return;
fa[x] = y;
del(lc(x), y);
del(rc(x), y);
}

压缩点

access 也应该变化 : $f[x]$ 可能已经经过压缩了。

 void access(int x) {
for (int y = ; x; y = x, x = f[y] = anc(f[x]))
splay(x), ch[x][] = y, up(x);
}

access

Code

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rd read()
using namespace std; const int N = 3e4 + ;
const int M = 1e5 + ; int n, m;
int fa[N], ans[N], vis[M]; struct edge {
int u, v; bool operator < (const edge &b) const {
return u == b.u ? v < b.v : u < b.u;
}
}e[M]; struct que {
int op, u, v;
}q[M]; int read() {
int X = , p = ; char c = getchar();
for (; c > '' || c < ''; c = getchar())
if (c == '-') p = -;
for (; c >= '' && c <= ''; c = getchar())
X = X * + c - '';
return X * p;
} int anc(int x) {
return fa[x] == x? x : fa[x] = anc(fa[x]);
} namespace LCT {
int f[N], sz[N], ch[N][], tun[N];
#define lc(x) ch[x][0]
#define rc(x) ch[x][1] int isroot(int x) {
return rc(f[x]) != x && lc(f[x]) != x;
} int get(int x) {
return rc(f[x]) == x;
} void rev(int x) {
swap(lc(x), rc(x));
tun[x] ^= ;
} void up(int x) {
sz[x] = ;
if (lc(x)) sz[x] += sz[lc(x)];
if (rc(x)) sz[x] += sz[rc(x)];
} void pushdown(int x) {
if (tun[x]) {
if (lc(x)) rev(lc(x));
if (rc(x)) rev(rc(x));
tun[x] = ;
}
} void pd(int x) {
if (!isroot(x))
pd(f[x]);
pushdown(x);
} void rotate(int x) {
int old = f[x], oldf = f[old], son = ch[x][get(x) ^ ];
if (!isroot(old)) ch[oldf][get(old)] = x;
ch[x][get(x) ^ ] = old;
ch[old][get(x)] = son;
f[son] = old; f[x] = oldf; f[old] = x;
up(old); up(x);
} void splay(int x) {
pd(x);
for (; !isroot(x); rotate(x))
if (!isroot(f[x]))
rotate(get(f[x]) == get(x) ? f[x] : x);
} void access(int x) {
for (int y = ; x; y = x, x = f[y] = anc(f[x]))
splay(x), ch[x][] = y, up(x);
} int findr(int x) {
access(x); splay(x);
while (lc(x)) pushdown(x), x = lc(x);
return x;
} void mroot(int x) {
access(x); splay(x); rev(x);
} void split(int x, int y) {
mroot(x); access(y); splay(y);
} void del(int x, int y) {
if (!x) return;
fa[x] = y;
del(lc(x), y);
del(rc(x), y);
} void link(int x, int y) {
mroot(x);
f[x] = y;
} void merge(int x, int y) {
x = anc(x); y = anc(y);
if (x == y)
return;
mroot(x);
if (findr(y) != x)
link(x, y);
else {
splay(x);
del(rc(x), x);
rc(x) = ; up(x);
}
}
} using namespace LCT; int main()
{
n = rd; m = rd;
for (int i = ; i <= n; ++i)
fa[i] = i;
for (int i = ; i <= m; ++i) {
e[i].u = rd; e[i].v = rd;
if (e[i].u > e[i].v)
swap(e[i].u, e[i].v);
}
sort(e + , e + + m);
int Q = ;
for (; ; ) {
int op = rd;
if (op == -)
break;
int u = rd, v = rd;
if (u > v)
swap(u, v);
q[++Q].op = op; q[Q].u = u;
q[Q].v = v;
edge t;
t.u = u; t.v = v;
if (op == )
vis[lower_bound(e + , e + + m, t) - e] = ;
}
for (int i = ; i <= m; ++i)
if (!vis[i])
merge(e[i].u, e[i].v);
for (int i = Q; i; i--) {
if (q[i].op == ) {
int x = q[i].u, y = q[i].v;
x = anc(x); y = anc(y);
if (x == y) {ans[i] = ; continue;}
split(x, y);
ans[i] = sz[y] - ;
}
else merge(q[i].u, q[i].v);
}
for (int i = ; i <= Q; ++i)
if (q[i].op == )
printf("%d\n", ans[i]);
}

BZOJ 1969 航线规划 - LCT 维护边双联通分量的更多相关文章

  1. [AHOI2005]航线规划——LCT维护边双联通分量

    因为只能支持加入一个边维护边双,所以时光倒流 维护好边双,每次就是提取出(x,y)的链,答案就是链长度-1 具体维护边双的话, void access(int x){ for(reg y=0;x;y= ...

  2. P2542 [AHOI2005]航线规划 LCT维护双连通分量

    \(\color{#0066ff}{ 题目描述 }\) 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel ...

  3. LCT 维护边双 / 点双的模板

    用 \(\text{LCT}\) 维护边双的做法是:加入一条非树边时,将这段树上路径合并为一个点代表这个边双,具体实现用并查集合并点,在 \(\text{Splay}\) 与 \(\text{Acce ...

  4. BZOJ 2959: 长跑 lct 双联通分量 并查集 splay

    http://www.lydsy.com/JudgeOnline/problem.php?id=2959 用两个并查集维护双联通分量的编号和合并. #include<iostream> # ...

  5. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

    [题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...

  6. BZOJ 压力 tarjan 点双联通分量+树上差分+圆方树

    题意 如今,路由器和交换机构建起了互联网的骨架.处在互联网的骨干位置的核心路由器典型的要处理100Gbit/s的网络流量. 他们每天都生活在巨大的压力之下.小强建立了一个模型.这世界上有N个网络设备, ...

  7. 『Tarjan算法 无向图的双联通分量』

    无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...

  8. 【UVA10972】RevolC FaeLoN (求边双联通分量)

    题意: 给你一个无向图,要求把所有无向边改成有向边,并且添加最少的有向边,使得新的有向图强联通. 分析: 这题的解法还是很好想的.先用边双联通分量缩点,然后找新图中入度为0和为1的点,入度为0则ans ...

  9. lightoj 1300 边双联通分量+交叉染色求奇圈

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1300 边双连通分量首先dfs找出桥并标记,然后dfs交叉着色找奇圈上的点.这题只要求在 ...

随机推荐

  1. MATLAB总结二

    1.如何将一个多项式中的系数按照幂次提取出来? sym2poly(ans) %ans为一个多项式. 2.在写第二份模式识别的大作业时遇到如下困难: 每个样本贡献给总概率的是一个关于x的表达式,我将所有 ...

  2. 一些常见的js问题总结

  3. SAP 000 客户端初始登录

    Solution 在SAP系统DB中删除账号SAP*,SAP系统会自动创建SAP*这个账号,然后初始密码是“PASS”,这样就获得Client 000 SAP*账号. Step by Step 以Or ...

  4. 媒体类型 & 媒体查询

    [媒体类型 & 媒体查询] @media 规则允许在相同样式表为不同媒体设置不同的样式. 在下面的例子告诉我们浏览器屏幕上显示一个14像素的Verdana字体样式.但是如果页面打印,将是10个 ...

  5. as3.0中如何阻止事件冒泡

    原作者:菩提树下的杨过转载出处:http://yjmyzz.cnblogs.com 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究 ...

  6. 使用Fiddler远程抓包(转载)

    转载自 http://www.cnblogs.com/111testing/p/6436372.html Fiddler简介以及web抓包 一.Fiddler简介 简单来说,Fiddler是一个htt ...

  7. oracle 创建包体的一些问题

    1. PLS-00201:必须声明标识符'A1' PLS-00304: 如果没有说明, 则无法编译'A1'主体 解决办法: 用sysdba身份 把A1包的执行权限给这个用户. 举例: 1.C:\Use ...

  8. jquery mobil 和页面适应

    <meta name="viewport" content="width=device-width" />

  9. c++面向过程和面向对象-C++编译器是如何管理类和对象的

    1,c++编译时如何区分对象调用类的方法? C++中的class从面向对象理论出发,将变量(属性)和函数(方法)集中定义在一起,用于描述现实世界中的类.从计算机的角度,程序依然由数据段(栈区内存)和代 ...

  10. Lua面试题目

    1.Lua的特性 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里. 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提 ...