bzoj2959: 长跑(lct+并查集)

本文探讨了在图论中使用双联通分量和并查集算法解决复杂问题的方法,通过维护整张图的双联通分量信息,结合lct数据结构,实现了高效查询和更新操作。

传送门
思路:题目中的有向边并没有什么用。。。
直接维护整张图的双联通分量的信息即可。
l c t lct lct和两个并查集分别维护点和双联通块的信息。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
    static char buf[rlen],*ib,*ob;
    (ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
    return ib==ob?-1:*ib++;
}
inline int read(){
    int ans=0;
    char ch=gc();
    while(!isdigit(ch))ch=gc();
    while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
    return ans;
}
const int N=150005;
int n,m,a[N],bcc[N],anc[N];
inline int Find(const int&x){return x^bcc[x]?bcc[x]=Find(bcc[x]):x;}
inline int find(const int&x){return x^anc[x]?anc[x]=find(anc[x]):x;}
typedef long long ll;
namespace lct{
    int son[N][2],siz[N],fa[N];
    ll sum[N],val[N];
    bool rev[N];
    inline bool which(const int&x){return x==son[Find(fa[x])][1];}
    inline bool isroot(const int&x){return !fa[x]||(x!=son[Find(fa[x])][0]&&x!=son[Find(fa[x])][1]);}
    inline void pushup(int p){siz[p]=siz[son[p][0]]+1+siz[son[p][1]],sum[p]=sum[son[p][0]]+val[p]+sum[son[p][1]];}
    inline void pushnow(int p){rev[p]^=1,swap(son[p][0],son[p][1]);}
    inline void pushdown(int p){
        if(!rev[p])return;
        rev[p]^=1;
        if(son[p][0])pushnow(son[p][0]);
        if(son[p][1])pushnow(son[p][1]);
    }
    inline void rotate(int x){
        int y=Find(fa[x]),z=Find(fa[y]),t=which(x);
        if(z&&!isroot(y))son[z][which(y)]=x;
        fa[x]=z,fa[y]=x,son[y][t]=son[x][t^1],son[x][t^1]=y;
        if(son[y][t])fa[son[y][t]]=y;
        pushup(y),pushup(x);
    }
    inline void splay(int x){
        static int stk[N],top;
        stk[top=1]=x;
        for(ri i=x;!isroot(i);i=Find(fa[i]))stk[++top]=Find(fa[i]);
        while(top)pushdown(stk[top--]);
        while(!isroot(x)){
            if(!isroot(Find(fa[x])))rotate(which(x)^which(Find(fa[x]))?x:Find(fa[x]));
            rotate(x);
        }
    }
    inline void access(int x){for(ri y=0;x;y=x,x=Find(fa[y]))splay(x),son[x][1]=y,pushup(x);}
    inline void makeroot(int x){access(x),splay(x),pushnow(x);}
    inline void dfs(int x,int rt){
        bcc[x]=rt;
        pushdown(x);
        if(son[x][0])dfs(son[x][0],rt);
        if(son[x][1])dfs(son[x][1],rt);
    }
    inline void link(int x,int y){makeroot(x),fa[x]=y;}
    inline void cut(int x,int y){makeroot(x),access(y),splay(y),fa[x]=son[y][0]=0,pushup(y);}
    inline void split(int x,int y){makeroot(x),access(y),splay(y);}
}
inline void link(int x,int y){anc[find(x)]=find(y),lct::link(x,y);}
inline void merge(int x,int y){
    lct::split(x,y);
    lct::val[y]=lct::sum[y];
    lct::dfs(y,y);
}
inline void update(int x,int y){
    int fx=Find(x);
    lct::splay(fx);
    lct::val[fx]-=a[x],a[x]=y,lct::val[fx]+=a[x];
    lct::pushup(fx);
}
inline void solve(int x,int y){
    if(find(x)^find(y))puts("-1");
    else if(x==y)cout<<lct::val[x]<<'\n';
    else lct::split(x,y),cout<<lct::sum[y]<<'\n';
}
int main(){
    n=read(),m=read();
    for(ri i=1;i<=n;++i)anc[i]=bcc[i]=i,a[i]=lct::sum[i]=lct::val[i]=read(),lct::siz[i]=1;
    for(ri op,u,v;m;--m){
        op=read(),u=read(),v=read();
        switch(op){
            case 1:{
                u=Find(u),v=Find(v);
                if(u^v){
                    if(find(u)^find(v))link(u,v);
                    else merge(u,v);
                }
                break;
            }
            case 2:{update(u,v);break;}
            case 3:{solve(Find(u),Find(v));break;}
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值