• BZOJ2959 长跑


    题目链接:戳我

    LCT维护树上连通块一类的题目。

    动态加边维护连通性最好还是用并查集来搞,时间复杂度貌似更优秀一点。

    主要难点是这道题目中有可能存在环,我们考虑缩点。我们要再开一个fa数组,来表示缩点之后的节点编号。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define MAXN 500010
    using namespace std;
    int n,m,top,tot;
    int bcj[MAXN],fa[MAXN],s[MAXN],w[MAXN];
    struct Node{int ff,sum,rev,v,ch[2];}t[MAXN<<2];
    
    inline int find_bcj(int x){return bcj[x]==x?x:bcj[x]=find_bcj(bcj[x]);}//这个是并查集
    
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}//这个是缩点之后的
    
    inline bool isroot(int x){return t[find(t[x].ff)].ch[0]!=x&&t[find(t[x].ff)].ch[1]!=x;}
    
    inline void push_up(int x){t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].v;}
    
    inline void rotate(int x)
    {
        int y=find(t[x].ff);
        int z=find(t[y].ff);
        int k=t[y].ch[1]==x;
        if(!isroot(y)) t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y; t[y].ff=x;
        push_up(y),push_up(x);
    }
    
    inline void push_down(int x)
    {
        if(t[x].rev)
        {
            swap(t[x].ch[0],t[x].ch[1]);
            t[t[x].ch[0]].rev^=1;
            t[t[x].ch[1]].rev^=1;
            t[x].rev^=1;
        }
    }
    
    inline void splay(int x)
    {
        s[top=1]=x=find(x);
        for(int i=x;!isroot(i);i=find(t[i].ff)) s[++top]=find(t[i].ff);
        while(top) push_down(s[top--]);
        while(!isroot(x))
        {
            int y=t[x].ff;
            int z=t[y].ff;
            if(!isroot(y))
                ((t[y].ch[0]==x)^(t[z].ch[0]==y))?rotate(x):rotate(y);
            rotate(x);
        }
    }
    
    inline void access(int x)
    {
        x=find(x);
        for(int y=0;x;y=x,x=find(t[x].ff))
            splay(x),t[x].ch[1]=y,push_up(x);
    }
    
    inline void makeroot(int x){x=find(x);access(x);splay(x);t[x].rev^=1;}
    
    inline void split(int x,int y){x=find(x),y=find(y);makeroot(x);access(y);splay(y);}
    
    inline void solve(int x,int ff)
    {
        fa[find(x)]=ff;
        t[ff].v+=t[x].v;
        t[ff].sum+=t[x].v;
        if(t[x].ch[0]) solve(t[x].ch[0],ff);
        if(t[x].ch[1]) solve(t[x].ch[1],ff);
    }
    
    inline void link(int x,int y)
    {
        int a=find_bcj(x),b=find_bcj(y);
        if(a==b)
        {
            x=find(x),y=find(y);
            ++tot;
            fa[tot]=bcj[tot]=tot;
            split(x,y);
            solve(y,tot);
        }
        else 
        {
            bcj[find_bcj(x)]=find_bcj(y);
            x=find(x),y=find(y);
            makeroot(x);
            t[x].ff=y;
        }
    }
    
    inline void update(int x,int k)
    {
        int ff=find(x);
        makeroot(ff);
        t[ff].v-=w[x];
        t[ff].v+=k;
        w[x]=k;
        push_up(find(ff));
    }
    
    inline int query(int x,int y)
    {
        int a=find_bcj(x),b=find_bcj(y);
        if(a!=b) return -1;
        a=find(x),b=find(y);
        split(a,b);
        return t[b].sum;
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        tot=n;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
            t[i].v=w[i];
            bcj[i]=fa[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            int p,a,b;
            scanf("%d%d%d",&p,&a,&b);
            //printf("p=%d a=%d b=%d
    ",p,a,b);
            if(p==1) link(a,b);
            else if(p==2) update(a,b);
            else if(p==3) printf("%d
    ",query(a,b));   
        }
        return 0;
    }
    
  • 相关阅读:
    复制延迟排查
    [学习笔记]贪心
    主从复制延时判断以及脚本
    [学习笔记]尺取法
    RESET MASTER 和RESET SLAVE 命令的使用方法 注意事项
    女神(goddess)——组合数学
    主从同步设置的重要参数log_slave_updates
    埃及分数&&The Rotation Game&&骑士精神——IDA*
    多源复制开关复制命令和监控
    万圣节后的早晨&&九数码游戏——双向广搜
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10447706.html
Copyright © 2020-2023  润新知