[BZOJ2959]长跑 LCT+双联通分量+并查集
2018-01-18 20:21
387 查看
首先在一个边双联通分量中所有点的贡献是都可以算入的。但是因为有加边操作,考虑用LCT来维护缩边双之后的树。
若一次连接的(x,y)在同一棵树上,就把x到y的路径提出来,缩成一个点。这可能会导致其他某些点的父亲标号改变,所以调用父亲之前一定要用并查集更新一下。
然后因为只有加边,判断在不在一棵树上最好也用并查集,用找根操作常数略大。
代码:
若一次连接的(x,y)在同一棵树上,就把x到y的路径提出来,缩成一个点。这可能会导致其他某些点的父亲标号改变,所以调用父亲之前一定要用并查集更新一下。
然后因为只有加边,判断在不在一棵树上最好也用并查集,用找根操作常数略大。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define N 150010 using namespace std; int n,m,fa ,w ,be ; int read() { int x=0;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar()); for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x; } int getfa(int v) { if(fa[v]==v) return v; return(fa[v]=getfa(fa[v])); } int getbe(int v) { if(be[v]==v) return v; return (be[v]=getbe(be[v])); } struct tree; tree *a ; struct tree { int t,sum,id; tree *s[2],*f; bool rev; tree(){t=sum=0;rev=0;s[0]=s[1]=f=NULL;} inline bool nfa() { if(f) f=a[getfa(f->id)]; } inline bool isroot() { nfa(); return (!f)||(f->s[0]!=this&&f->s[1]!=this); } inline bool son() { return f->s[1]==this; } inline void update() { sum=t+(s[0]?s[0]->sum:0)+(s[1]?s[1]->sum:0); } inline void reverse() { rev^=1;swap(s[0],s[1]); } inline void pushdown() { if(rev) { if(s[0]) s[0]->reverse(); if(s[1]) s[1]->reverse(); rev=0; } } void rotate() { pushdown(); bool b=son()^1; f->s[b^1]=s[b]; if(s[b]) s[b]->f=f; s[b]=f;f=f->f;s[b]->f=this; if(f&&f->s[0]==s[b]) f->s[0]=this; else if(f&&f->s[1]==s[b]) f->s[1]=this; s[b]->update(); update(); } void splay() { while(!isroot()) if(f->isroot()) f->pushdown(),rotate(); else { f->f->nfa(); f->f->pushdown(); f->pushdown(); if(son()^f->son()) f->rotate(); else rotate(); rotate(); } } void access() { for(tree *x=this,*y=NULL;x;y=x,x->nfa(),x=x->f) x->splay(),x->pushdown(),x->s[1]=y,x->update(); } void makeroot() { access(); splay(); reverse(); } void link(tree *y) { makeroot(); f=y; } void split(tree *y) { y->makeroot(); access(); splay(); } void modify(int c) { splay(); t=sum=c; } void merge(tree *x) { if(x!=this) x->t+=t; if(getfa(x->id)!=getfa(id)) fa[fa[id]]=fa[x->id]; if(s[0]) s[0]->merge(x); if(s[1]) s[1]->merge(x); s[0]=s[1]=f=NULL; if(x!=this)t=sum=0; rev=0; } }; int main() { n=read();m=read(); for(int i=1;i<=n;i++) { w[i]=read(); (a[i]=new tree)->modify(w[i]); a[i]->id=fa[i]=be[i]=i; } while(m--) { int opt=read(),x=read(),y=read(); if(opt!=2) x=getfa(x),y=getfa(y); if(opt==1) { if(getbe(x)!=getbe(y)) be[be[y]]=be[x],a[x]->link(a[y]); else if(x!=y) { a[x]->split(a[y]); a[x]->merge(a[x]); } } if(opt==2) { getfa(x); a[fa[x]]->modify(a[fa[x]]->t-w[x]+y); w[x]=y; } if(opt==3) { if(getbe(x)!=getbe(y)) {puts("-1");continue;} a[x]->split(a[y]); printf("%d\n",a[x]->sum); } } return 0; }
相关文章推荐
- BZOJ 2959: 长跑 [lct 双连通分量 并查集]
- 【LCT+并查集】BZOJ2959[长跑]题解
- [BZOJ2959][清橙1379]长跑-LCT-并查集
- 【BZOJ2959】【codevs2002】长跑,维护双联通分量
- 【NOIP2017练习&BZOJ4998】星球联盟(强联通分量,并查集)
- [BZOJ2959]长跑(LCT)
- [AHOI2005]【bzoj1969】LANE 航线规划——LCT维护双联通分量
- 【bzoj2959】长跑【LCT+并查集】
- [LCT BZOJ]2959: 长跑
- bzoj 2959: 长跑 lct
- [LCT 边双连通分量缩点] BZOJ 2959 长跑
- 【BZOJ2959】长跑(Link-Cut Tree,并查集)
- 【BZOJ2959】长跑(Link-Cut Tree,并查集)
- BZOJ 2959 长跑
- bzoj 2959: 长跑 lct+并查集
- BZOJ 4025|二分图|CDQ分治|并查集|LCT
- BZOJ 2730 [HNOI2012]矿场搭建 点双联通分量(割点)
- bzoj 2959 长跑(LCT+BCC+并查集)
- 【强联通分量缩点】【最短路】【spfa】bzoj1179 [Apio2009]Atm
- UVa247电话圈(强联通分量--传递闭包+并查集 or tarjan算法)