Description
对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。
星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。
一些先遣飞船已经出发,在星球之间开辟探险航线。
探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。
例如下图所示:
![](https://www.lydsy.com/JudgeOnline/images/1969.jpg)
在5个星球之间,有5条探险航线。
A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。
显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。
然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。
假设在上图中,航线4-2(从4号星球到2号星球)被破坏。
此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。
小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。
现在请你帮助完成。
Input
第一行有两个整数N,M。表示有N个星球(1< N < 30000),初始时已经有M条航线(1 < M < 100000)。
随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。
接下来每行有三个整数C、A、B。
C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复;
C为-1表示输入文件结束,这时该行没有A,B的值。
被破坏的航线数目与询问的次数总和不超过40000。
Output
对每个C为1的询问,输出一行一个整数表示关键航线数目。
注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。
在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。
Sample Input
5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1
Sample Output
1
3
3
题解Here!
网上一堆树链剖分套树状数组/线段树维护双连通分量,但是我不会啊。
其实我是懒得写了。。。
首先,时光倒流,把删边操作变成加边操作。
这个套路了吧。。。
然后用$LCT$维护两点间的桥边数量。
首先缩点,变成一棵树。
我们发现每次加边会形成一个环。
将环缩点,也就是将环上的的点的父亲改为$Splay$重链的根。
为什么这样是正确的呢?
我们$makeroot(x)$之后,$x$在原树的子树就到了它的右子树,即$a[x].son[1]$。
那么我们只需要把此时整个右子树加上$x$缩成一个点,即把它们在并查集中的父节点均变为$x$在并查集中的父节点。
这样就是对的。
至于怎么改,就暴力递归就好了。
每次查询就是子树大小$-1$。
然后是代码。
$access(x)$操作魔改了一下。
还有$findroot(x)$最后要$splay(x)$。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 200010
using namespace std;
int n,m,q=0;
int fa[MAXN],ans[MAXN];
int top=0,stack[MAXN];
bool used[MAXN];
struct Link_Cut_Tree{
int son[2];
int f,v,flag;
}a[MAXN];
struct Graph{
int x,y;
bool operator <(const Graph &p)const{
return (x<p.x||(x==p.x&&y<p.y));
}
}b[MAXN];
struct Question{
int f,x,y;
}que[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool isroot(int rt){
return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
}
inline void pushup(int rt){
if(!rt)return;
a[rt].v=a[a[rt].son[0]].v+a[a[rt].son[1]].v+1;
}
inline void pushdown(int rt){
if(!rt||!a[rt].flag)return;
a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
swap(a[rt].son[0],a[rt].son[1]);
}
inline void turn(int rt){
int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
if(!isroot(x)){
if(a[y].son[0]==x)a[y].son[0]=rt;
else a[y].son[1]=rt;
}
a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
pushup(x);pushup(rt);
}
void splay(int rt){
top=0;
stack[++top]=rt;
for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
while(top)pushdown(stack[top--]);
while(!isroot(rt)){
int x=a[rt].f,y=a[x].f;
if(!isroot(x)){
if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
else turn(x);
}
turn(rt);
}
}
inline void access(int rt){
for(int i=0;rt;i=rt,rt=a[i].f=find(a[rt].f)){//这里魔改了一下,因为要维护换的父亲
splay(rt);
a[rt].son[1]=i;
pushup(rt);
}
}
inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
int findroot(int rt){
access(rt);splay(rt);
while(a[rt].son[0])rt=a[rt].son[0];
splay(rt);//我也不知道
return rt;
}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
void change(int rt,int ancestry){
if(!rt)return;
fa[rt]=ancestry;
if(a[rt].son[0])change(a[rt].son[0],ancestry);
if(a[rt].son[1])change(a[rt].son[1],ancestry);
}
inline void link(int x,int y){
if(x==y)return;
makeroot(x);
if(findroot(y)!=x){
a[x].f=y;
return;
}
change(a[x].son[1],x);
a[x].son[1]=0;
pushup(x);
}
inline int query(int x,int y){split(x,y);return a[y].v-1;}
void work(){
int x,y;
for(int i=q;i>=1;i--){
ans[i]=-1;
x=find(que[i].x);y=find(que[i].y);
if(que[i].f==0)link(x,y);
else ans[i]=query(x,y);
}
for(int i=1;i<=q;i++)if(ans[i]!=-1)printf("%d\n",ans[i]);
}
void init(){
int x,y;
n=read();m=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
b[i].x=read();b[i].y=read();
used[i]=true;
if(b[i].x>b[i].y)swap(b[i].x,b[i].y);
}
sort(b+1,b+m+1);
while(1){
int f=read();
if(f==-1)break;
q++;
que[q].f=f;que[q].x=read();que[q].y=read();
if(que[q].x>que[q].y)swap(que[q].x,que[q].y);
if(que[q].f==0)used[lower_bound(b+1,b+m+1,(Graph){que[q].x,que[q].y})-b]=false;
}
for(int i=1;i<=m;i++)if(used[i])link(find(b[i].x),find(b[i].y));
}
int main(){
init();
work();
return 0;
}