BZOJ 2959 长跑 Link-Cut-Tree+并查集

来源:互联网 发布:什么软件,歌很全 编辑:程序博客网 时间:2024/04/29 03:00

题目大意:给定n个点,支持以下操作:
1.在某两个点之间连接一条无向边
2.改变某个点的权值
3.将每条边设定一个方向,然后从x走到y,求能经过的所有点的权值和
首先如果这个图是静态的,我们把边双都缩点,那么每次询问显然就是两个点所在边双路径上的点权和
现在图是动态的,因此我们用动态树维护一下就行了
如果连边的两个点不连通,就在LCT中连接这两个点
如果连边的两个点已经连通,就将这个两个点路径上的所有点用并查集缩点
时间复杂度O(mlogn)
似乎用链剖会快一些?

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 150100using namespace std;int n,m;int a[M];struct Union_Find_Set{    int fa[M];    int Find(int x)    {        if(!fa[x]||fa[x]==x)            return fa[x]=x;        return fa[x]=Find(fa[x]);    }    void Union(int x,int y)    {        x=Find(x);y=Find(y);        if(x==y) return ;        fa[x]=y;    }}s1,s2;namespace Link_Cut_Tree{    struct abcd{        abcd *ls,*rs,*fa;        int val,sum;        bool rev_mark;        abcd() {}        abcd(int x);        void Push_Up();        void Push_Down();        void Reverse();    }tree[M],*null=&tree[0];    abcd :: abcd(int x)    {        ls=rs=fa=null;        val=sum=x;        rev_mark=false;    }    void abcd :: Push_Up()    {        sum=ls->sum+rs->sum+val;    }    void abcd :: Push_Down()    {        if(fa->ls==this||fa->rs==this)            fa->Push_Down();        if(rev_mark)        {            ls->Reverse();            rs->Reverse();            rev_mark=false;        }    }    void abcd :: Reverse()    {        swap(ls,rs);        rev_mark^=1;    }    void Zig(abcd *x)    {        abcd *y=x->fa;        y->ls=x->rs;        x->rs->fa=y;        x->rs=y;        x->fa=y->fa;        if(y==y->fa->ls)            y->fa->ls=x;        else if(y==y->fa->rs)            y->fa->rs=x;        y->fa=x;        y->Push_Up();    }    void Zag(abcd *x)    {        abcd *y=x->fa;        y->rs=x->ls;        x->ls->fa=y;        x->ls=y;        x->fa=y->fa;        if(y==y->fa->ls)            y->fa->ls=x;        else if(y==y->fa->rs)            y->fa->rs=x;        y->fa=x;        y->Push_Up();    }    void Splay(abcd *x)    {        x->Push_Down();        while(x->fa->ls==x||x->fa->rs==x)        {            abcd *y=x->fa,*z=y->fa;            if(x==y->ls)            {                if(y==z->ls)                    Zig(y);                Zig(x);            }            else            {                if(y==z->rs)                    Zag(y);                Zag(x);            }        }        x->Push_Up();    }    void Access(abcd *x)    {        abcd *y=null;        while(x!=null)        {            Splay(x);            x->rs=y;            x->Push_Up();            x->fa=&tree[s2.Find(x->fa-tree)];            y=x;x=x->fa;        }    }    void Move_To_Root(abcd *x)    {        Access(x);        Splay(x);        x->Reverse();    }    void Link(abcd *x,abcd *y)    {        Move_To_Root(x);        x->fa=y;    }    void Reduction(abcd *&x,abcd *y)    {        if(x==null)            return ;        s2.Union(x-tree,y-tree);        y->val+=x->val;        Reduction(x->ls,y);        Reduction(x->rs,y);        x=null;    }}namespace IStream{    #define L (1<<16)    char Get_Char()    {        static char buffer[M],*S,*T;        if(S==T)        {            T=(S=buffer)+fread(buffer,1,L,stdin);            if(S==T) return EOF;        }        return *S++;    }    int Get_Int()    {        int re=0;        char c=Get_Char();        while(c<'0'||c>'9')            c=Get_Char();        while(c>='0'&&c<='9')            re=(re<<3)+(re<<1)+(c-'0'),c=Get_Char();        return re;    }}int main(){    using namespace Link_Cut_Tree;    using namespace IStream;    int i,p,x,y;    cin>>n>>m;    for(i=1;i<=n;i++)    {        a[i]=Get_Int();        tree[i]=abcd(a[i]);    }    for(i=1;i<=m;i++)    {        p=Get_Int();        x=Get_Int();        y=Get_Int();        if(p==1)        {            x=s2.Find(x);y=s2.Find(y);            if(x==y) continue ;            if(s1.Find(x)!=s1.Find(y))                Link(&tree[x],&tree[y]),s1.Union(x,y);            else            {                Move_To_Root(&tree[x]);                Access(&tree[y]);                Splay(&tree[y]);                Reduction(tree[y].ls,&tree[y]);                Reduction(tree[y].rs,&tree[y]);                tree[y].Push_Up();            }        }        else if(p==2)        {            Splay(&tree[s2.Find(x)]);            tree[s2.Find(x)].val+=y-a[x];            tree[s2.Find(x)].Push_Up();            a[x]=y;        }        else        {            x=s2.Find(x);y=s2.Find(y);            if(s1.Find(x)!=s1.Find(y))                puts("-1");            else            {                Move_To_Root(&tree[x]);                Access(&tree[y]);                Splay(&tree[y]);                printf("%d\n",tree[y].sum);            }        }    }    return 0;}
1 0
原创粉丝点击