[BZOJ2959]长跑(LCT+并查集)
用LCT支持:在线加边,单点修改,求一个两个点路径上的所有边BCC的点权和。
用LCT维护边BCC的形态(即缩边双之后的树),2,3操作都是LCT基本操作,重点考虑加边操作。
当这条边的两个端点属于同一BCC时显然没有任何影响。当两个端点不在同一个连通块里时直接在LCT上做link(bel[x],bel[y])即可。
当两个端点在同一个连通块里但不在同一个BCC中时,相当于将(缩点后的)树上两个点之间的路径全部缩成一个点。
由于过程中有频繁的点合并操作,所以再拿一个并查集记录每个BCC目前真正属于哪个BCC(即它被合并到哪个点去了),链合并的时候,先split(x,y)分离出这条链,再将链上所有点的fa[](并查集上的父亲)全部设为y,再将y左子树整个删去。在LCT操作中,我们所有的f[x](LCT上的父亲)全部变为find(f[x]),这样那些链上连出去的虚子树就能找到自己的新父亲(y)了。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=150010; 7 int n,m,op,x,y,v[N],f[N],fa1[N],fa2[N],c[N][2],w[N],sm[N],rev[N]; 8 9 int get1(int x){ return x==fa1[x] ? x : fa1[x]=get1(fa1[x]); } 10 int get2(int x){ return x==fa2[x] ? x : fa2[x]=get2(fa2[x]); } 11 void upd(int x){ sm[x]=sm[c[x][0]]+sm[c[x][1]]+w[x]; } 12 void push(int x){ if (rev[x]) swap(c[x][0],c[x][1]),rev[c[x][0]]^=1,rev[c[x][1]]^=1,rev[x]=0; } 13 bool isrt(int x){ return c[get1(f[x])][1]!=x && c[get1(f[x])][0]!=x; } 14 void pd(int x){ if (!isrt(x)) pd(get1(f[x])); push(x); } 15 16 void rot(int x){ 17 int y=get1(f[x]),z=get1(f[y]),w=(c[y][1]==x); 18 if (!isrt(y)) c[z][c[z][1]==y]=x; 19 f[x]=z; f[y]=x; f[c[x][w^1]]=y; 20 c[y][w]=c[x][w^1]; c[x][w^1]=y; upd(y); 21 } 22 23 void splay(int x){ 24 for (pd(x); !isrt(x); rot(x)){ 25 int y=get1(f[x]),z=get1(f[y]); 26 if (!isrt(y)) rot((c[y][0]==x)^(c[z][0]==y)?x:y); 27 } 28 upd(x); 29 } 30 31 void access(int x){ for (int y=0; x; y=x,x=get1(f[x])) splay(x),c[x][1]=y,upd(x); } 32 void mkrt(int x){ access(x); splay(x); rev[x]^=1; } 33 void link(int x,int y){ mkrt(x); f[x]=y; } 34 void split(int x,int y){ mkrt(x); access(y); splay(y); } 35 void cut(int x,int y){ split(x,y); c[y][0]=f[x]=0; upd(y); } 36 37 void dfs(int x,int y){ 38 fa1[x]=y; push(x); 39 if (c[x][0]) dfs(c[x][0],y); 40 if (c[x][1]) dfs(c[x][1],y); 41 } 42 43 int main(){ 44 freopen("bzoj2959.in","r",stdin); 45 freopen("bzoj2959.out","w",stdout); 46 scanf("%d%d",&n,&m); 47 rep(i,1,n) scanf("%d",&w[i]),sm[i]=v[i]=w[i],fa1[i]=fa2[i]=i; 48 rep(i,1,m){ 49 scanf("%d%d%d",&op,&x,&y); int tx=get1(x),ty=op==2?0:get1(y); 50 if (op==1){ 51 if (tx==ty) continue; 52 if (get2(tx)!=get2(ty)) link(tx,ty),fa2[get2(tx)]=get2(ty); 53 else split(tx,ty),w[ty]=sm[ty],dfs(ty,ty),c[ty][0]=0; 54 } 55 if (op==2) splay(tx),w[tx]+=y-v[x],sm[tx]+=y-v[x],v[x]=y; 56 if (op==3){ 57 if (get2(tx)!=get2(ty)) puts("-1"); 58 else split(tx,ty),printf("%d\n",sm[ty]); 59 } 60 } 61 return 0; 62 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 一个适用于 .NET 的开源整洁架构项目模板
· AI Editor 真的被惊到了
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手
· 关于linux网桥(Linux Bridge)的一些个人记录
2018-04-02 [BZOJ4815][CQOI2017]小Q的表格(莫比乌斯反演)
2018-04-02 [BZOJ2226][SPOJ5971]LCMSum(莫比乌斯反演)
2018-04-02 [BZOJ4813][CQOI2017]小Q的棋盘(DP,贪心)
2018-04-02 [BZOJ3990][SDOI2015]排序(DFS)
2018-04-02 [BZOJ4836]二元运算(分治FFT)