BZOJ1969: [Ahoi2005]LANE 航线规划
Description
对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。
星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。
一些先遣飞船已经出发,在星球之间开辟探险航线。
探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。
例如下图所示:
在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; }