因为只能支持加入一个边维护边双,所以时光倒流

维护好边双,每次就是提取出(x,y)的链,答案就是链长度-1

具体维护边双的话,

void access(int x){
for(reg y=0;x;y=x,x=t[y].fa=fin(t[x].fa)){//注意更新
splay(x);rs=y;pushup(x);
}
}

dele(int x,int y)把x节点的father指向y,这个x临死前把信息指到y,以便于后面要找x的直接找y即可。{

  if(x) fa[x]=y,dele(rs,y),dele(ls,y)
}

merge函数(int x,int y){

  if(x==y(在一起))return 什么都不用做

  makert(x)

  if(findrt(y)!=x){

    t[x].fa=y相当于直接link

    return;

  }

  splay(x)

  出环了。那么要缩点,x现在是根,并且作为代表点

  dele(rs,x)

  t[x].ch[1]=0,干掉子树,这个子树已经名存实亡了。

  pushup(x)

}

我通过merge,dele函数打上标记,

在access的时候把标记依次还原,达到真正缩点的目的。

而并查集使我每次都会到真正的节点。不会到已经删除的节点。

代码:

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
#define ls t[x].ch[0]
#define rs t[x].ch[1]
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=+;
const int M=+;
int n,m;
struct node{
int sz,fa,ch[],r;
}t[N];
int fa[N];
int fin(int x){
return fa[x]==x?x:fa[x]=fin(fa[x]);
}
bool nrt(int x){
return (t[t[x].fa].ch[]==x)||(t[t[x].fa].ch[]==x);
}
void rev(int x){
swap(t[x].ch[],t[x].ch[]);
t[x].r^=;
}
void pushdown(int x){
if(t[x].r){
t[x].r=;
rev(ls);rev(rs);
}
}
void pushup(int x){
t[x].sz=t[ls].sz+t[rs].sz+;
}
void rotate(int x){
int y=t[x].fa,d=t[y].ch[]==x;
t[t[y].ch[d]=t[x].ch[!d]].fa=y;
if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[]==y]=x;
else t[x].fa=t[y].fa;
t[t[y].fa=x].ch[!d]=y;
pushup(y);
}
int sta[N];
void splay(int x){
int y=x,z=;
sta[++z]=y;
while(nrt(y)) y=t[y].fa,sta[++z]=y;
while(z) pushdown(sta[z--]); while(nrt(x)){
y=t[x].fa,z=t[y].fa;
if(nrt(y)){
rotate(((t[y].ch[]==x)==(t[z].ch[]==y))?y:x);
}
rotate(x);
}
pushup(x);
}
void access(int x){
for(reg y=;x;y=x,x=t[y].fa=fin(t[x].fa)){
splay(x);rs=y;pushup(x);
}
}
void makert(int x){
access(x);splay(x);rev(x);
}
int findrt(int x){
access(x);splay(x);
pushdown(x);
while(t[x].ch[]) pushdown(x=t[x].ch[]);
splay(x);
return x;
}
void dele(int x,int y){
if(x) fa[x]=y,dele(ls,y),dele(rs,y);
}
void merge(int x,int y){
if(x==y) return;
makert(x);
if(findrt(y)!=x){
t[x].fa=y;
pushup(y);
return;
}
dele(t[x].ch[],x);
t[x].ch[]=;
pushup(x);
}
void split(int x,int y){
makert(x);access(y);splay(y);
}
struct edge{
int x,y;
bool friend operator <(edge a,edge b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
}e[M];
bool vis[M];
struct que{
int c;
int x,y;
}q[M];
int ans[M],cnt;
int main(){
rd(n);rd(m);
int x,y;
for(reg i=;i<=n;++i){
fa[i]=i;t[i].sz=;
}
for(reg i=;i<=m;++i){
rd(x);rd(y);
if(x>y) swap(x,y);
e[i].x=x;e[i].y=y;
}
sort(e+,e+m+);
int c;
int tot=;
while(){
rd(c);
if(c==-) break;
++tot;
rd(x);rd(y);
if(x>y) swap(x,y);
if(c==){
edge lp;lp.x=x,lp.y=y;
vis[lower_bound(e+,e+m+,lp)-e]=;
}
q[tot].x=x,q[tot].y=y;
q[tot].c=c;
} for(reg i=;i<=m;++i){
if(!vis[i]){
x=fin(e[i].x),y=fin(e[i].y);
merge(x,y);
}
}
for(reg i=tot;i>=;--i){
x=fin(q[i].x);y=fin(q[i].y);
if(q[i].c==){
++cnt;
split(x,y);
ans[cnt]=t[y].sz-;
}
else{
merge(x,y);
}
}
for(reg i=cnt;i>=;--i){
printf("%d\n",ans[i]);
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2018/12/19 9:57:28
*/

[AHOI2005]航线规划——LCT维护边双联通分量的更多相关文章

  1. BZOJ 1969 航线规划 - LCT 维护边双联通分量

    Solution 实际上就是查询 $u$ 到 $v$ 路径上 边双的个数 $ -1$. 并且题目仅有删边, 那么就离线倒序添边. 维护 边双 略有不同: 首先需要一个并查集, 记录 边双内的点. 在 ...

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

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

  3. AHOI2005航线规划 bzoj1969(LCT缩点)

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  4. P2542 【[AHOI2005]航线规划】

    P2542 [[AHOI2005]航线规划] 一个无向图,m个操作 删去一条边 给定两个点,求有多少边使得如果这条边不存在,给定的两个点不连通 一般这种删边的题目,考虑逆序加边处理 在删完的图中,任意 ...

  5. 洛谷 P2542 [AHOI2005]航线规划 解题报告

    P2542 [AHOI2005]航线规划 题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系--一个巨大的由千百万星球构成的Samuel星系 ...

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

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

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

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

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

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

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

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

随机推荐

  1. python学习——函数

     一.在python的世界里什么是函数: 答:函数通常是用来实现某一个功能二被封装成的一个对象,是用来实现代码复用的常用方式 现在有一个需求,假如你在不知道len()方法的情况下,要你计算字符串‘he ...

  2. stm32f103 time2配置,转载

    //----------------------------main()-------------------- //stm32f103c8t6有3个普通1个高级定时器 //每次进入中断服务程序间隔时 ...

  3. 10---git安装

    卸载原来的版本: # 查看版本 git --version # 移除原来的版本 yum remove git 安装依赖库: yum install curl-devel expat-devel get ...

  4. mysql5.7.19安装报错 无法定位程序输入点

    https://blog.csdn.net/t876587201/article/details/79503688

  5. python--基本类型之列表

    Lest(列表): 定义和创建列表: 列表:是python以及其他语言中最常用的数据结构之一.python用 [] 来解析列表列表是可变的.--可以改变列表的内容可以用切片 a=['张三','李四', ...

  6. c/c++ 随机数生成

    当程序需要一个随机数时有两种情况下使用: 1.程序中只需使用一次随机数,则调用rand()函数即可 2.程序需要多次使用随机数,那么需要使用srand()函数生成随机数种子在调用rand()函数保证每 ...

  7. DDoS 攻击与防御:从原理到实践(下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. DDoS 攻击与防护实践 DDoS 攻击的实现方式主要有如下两种: 自建 DDoS 平台 现在有开源的 DDoS 平台源代码,只要有足够机器和带宽资 ...

  8. Apache 配置说明

    ServerRoot ServerRoot: The top of the directory tree under which the server's configuration, error, ...

  9. 【多线程】 Task ,async ,await

    [多线程]Task ,async ,await 一. WinForm 里经常会用到多线程, 多线程的好出就不多说了,来说说多线程比较麻烦的地方 1. UI 线程与其他线程的同步,主要是 Form 和 ...

  10. 《python核心编程第二版》第1章练习

    1–1. 安装 Python.请检查 Python 是否已经安装到你的系统上,如果没有,请下载并 安装它 略 1–2.  执行 Python.有多少种运行 Python 的不同方法?你喜欢哪一种?为什 ...