【LCT维护基环内向树森林】BZOJ4764 弹飞大爷
4764: 弹飞大爷
Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 101 Solved: 52
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 1 1
1 1
1 2
1 3
2 1 2
1 1
1 2
1 3
2 3 -1
1 1
1 2
1 3
2 2 233
1 1
1 2
1 3
2 2 -233
1 1
1 2
1 3
Sample Output
3
2
1
2
2
1
-1
-1
-1
3
1
2
3
1
2
题解
LCT维护基环内向树森林
具体来说,就是当我们原来维护的无向图变成了一个每个点出度为1的有向图
显然它是可能存在环的,并且更重要的是它不能换根(方向问题)
所以若它是一棵树的话,正常维护LCT
如果它形成了环,我们记一下这个联通块的根到达的点的位置pos[i]
对于Link操作,我们判断一下这条有向边x—>y的端点y在被连接之前的根节点是否已经可以是x
- 如果是,那么加上这条边之后形成环,我们显然不能把它加上,所以我们令pos[x]=y
- 如果不是,正常地把x连到y的下面
对于Cut操作,我们要判断一下这条有向边x—>y的端点x形成的环是否正好连到y,即判断pos[x]是否等于y
- 如果是,那么直接把环去掉,即令pos[x]=0
- 如果不是,我们先记一下x在联通块中的根节点rt,然后正常地去掉这条边
- 但是然后我们还要判断一下割断这条边后是否会保留原来的环,如果已经没环,就把记录的边加上,如果环还在,退出
具体看代码吧
代码
//by 减维 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<bitset> #include<set> #include<cmath> #include<vector> #include<set> #include<map> #include<ctime> #include<algorithm> #define ll long long #define il inline #define rg register #define db double #define mpr make_pair #define maxn 200005 #define inf (1<<30) #define eps 1e-8 #define pi 3.1415926535897932384626L using namespace std; inline int read() { int ret=0;bool fla=0;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-'){fla=1;ch=getchar();} while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();} return fla?-ret:ret; } int n,m,fa[maxn],son[maxn][2],siz[maxn],rev[maxn],pos[maxn]; int a[maxn]; il bool pdp(int x){return son[fa[x]][1]==x;} il bool isrt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;} il void rever(int x){rev[x]^=1;swap(son[x][0],son[x][1]);} il void upda(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;} il void pdn(int x) { if(rev[x]) { if(son[x][0]) rever(son[x][0]); if(son[x][1]) rever(son[x][1]); rev[x]=0; } } void pd(int x){if(!isrt(x)) pd(fa[x]);pdn(x);} il void rot(int x) { int f=fa[x],g=fa[f],o=pdp(x); if(!isrt(f)) son[g][pdp(f)]=x;fa[x]=g; son[f][o]=son[x][!o];fa[son[f][o]]=f; son[x][!o]=f;fa[f]=x; upda(f),upda(x); } il void splay(int x) { pd(x); for(;!isrt(x);rot(x)) if(!isrt(fa[x])) rot(pdp(fa[x])==pdp(x)?fa[x]:x); } il void acc(int x) { for(int y=0;x;y=x,x=fa[x]) splay(x),son[x][1]=y,upda(x); } il int find(int x) { acc(x),splay(x); while(son[x][0]) pdn(x),x=son[x][0]; return x; } il void link(int x,int y) { if(find(y)==x) pos[x]=y; else acc(x),splay(x),fa[x]=y; } il void cut(int x,int y) { if(pos[x]==y) pos[x]=0; else{ int t=find(x); acc(x),splay(x),fa[son[x][0]]=0,son[x][0]=0,upda(x); if(pos[t]&&find(pos[t])!=t) link(t,pos[t]),pos[t]=0; } } int main() { n=read(),m=read(); for(int i=1;i<=n;++i) a[i]=read(),siz[i]=1; for(int i=1;i<=n;++i) if(i+a[i]>=1&&i+a[i]<=n) link(i,a[i]+i); for(int i=1,op,x,y;i<=m;++i) { op=read(),x=read(); if(op==1){ acc(x),y=find(x); if(pos[y]) puts("-1"); else splay(x),printf("%d\n",siz[x]); }else{ y=read(); if(x+a[x]>=1&&a[x]+x<=n) cut(x,a[x]+x); if(x+y>=1&&x+y<=n) link(x,x+y); a[x]=y; } } return 0; }