BZOJ 2001 Hnoi2010 城市建設 分治+LCT

題目大意:給定一張帶權無向圖,每次改變一條邊的邊權並詢問最小生成樹,不強制在線

日狗我爲什麼要寫這個JB算法。。。

對時間進行分治,每條邊的存在時間爲一個區間,拆成log 個;
帶着LCT把分治結構DFS一遍,一個節點入棧時用上面的所有邊扔進LCT動態維護最小生成樹,出棧時還原所有操作

時間複雜度O(nlog2n)

如果沒有特殊的卡常技巧請不要寫這個算法

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;

namespace IStream{  
    const int _L=1<<15; 
    char buffer[_L],*S,*T;  
    inline char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,_L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;
    }  
    inline int Get_Int()  
    {  
        char c;  
        int re=0;  
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());  
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
        return re;  
    }  
}

class OStream{  
    private:  
        static const int _L=1<<15;  
        char stack[30];int top;  
        char buffer[_L],*S;  
    public:  
        OStream()  
        {  
            S=buffer;  
        }  
        void Put_Long_Long(long long x)  
        {  
            stack[++top]='\n';
            if(!x) stack[++top]='0';  
            else while(x)  
                stack[++top]=x%10+'0',x/=10;  
            while(top)  
            {  
                if(S==buffer+_L)  
                {  
                    fwrite(buffer,1,_L,stdout);
                    S=buffer;  
                }  
                *S++=stack[top--];  
            }  
        }  
        ~OStream()  
        {  
            *S=0;  
            fwrite(buffer,1,S-buffer,stdout);
        }  
}os;

int n,m,q;
int tim[M];

namespace Link_Cut_Tree{
    struct abcd{
        abcd *ls,*rs,*fa;
        int x,y,z;
        abcd *max_val;
        bool rev_mark;
        abcd() {}
        abcd(int,int,int);
        void Push_Up();
        void Push_Down();
        void Reverse();
    }mempool[70700],*C=mempool,*tree[M],*edges[M],*null=new (C++)abcd(0,0,-1);

    abcd :: abcd(int _,int __,int ___)
    {
        ls=rs=fa=null;
        x=_;y=__;z=___;
        max_val=this;
        rev_mark=false;
    }

    void abcd :: Push_Up()
    {
        max_val=this;
        if(ls->max_val->z > max_val->z)
            max_val=ls->max_val;
        if(rs->max_val->z > max_val->z)
            max_val=rs->max_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();
            y=x;x=x->fa;
        }
    }

    void Move_To_Root(abcd *x)
    {
        Access(x);
        Splay(x);
        x->Reverse();
    }

    bool Connected(abcd *x,abcd *y)
    {
        while(x->fa!=null)
            x=x->fa;
        while(y->fa!=null)
            y=y->fa;
        return x==y;
    }

    void Link(abcd *x,abcd *y)
    {
        Move_To_Root(x);
        x->fa=y;
    }

    void Cut(abcd *x,abcd *y)
    {
        Move_To_Root(x);
        Access(y);
        Splay(y);
        y->ls=null;
        x->fa=null;
        y->Push_Up();
    }

}

struct List{
    int num,val,next;
}table[100100*20];
int head[M<<2],tot;

void Insert(int p,int x,int y,int l,int r,int num,int val)
{
    int mid=x+y>>1;
    if(x==l&&y==r)
    {
        table[++tot].num=num;
        table[  tot].val=val;
        table[  tot].next=head[p];
        head[p]=tot;
        return ;
    }
    if(r<=mid)
        Insert(p<<1,x,mid,l,r,num,val);
    else if(l>mid)
        Insert(p<<1|1,mid+1,y,l,r,num,val);
    else
        Insert(p<<1,x,mid,l,mid,num,val) , Insert(p<<1|1,mid+1,y,mid+1,r,num,val) ;
}

pair<bool,Link_Cut_Tree::abcd*> operations[200200];int top; //0-刪除 1-插入

void Divide_And_Conquer(int p,int x,int y,long long ans)
{
    using namespace Link_Cut_Tree;
    int i,bottom=top,mid=x+y>>1;
    for(i=head[p];i;i=table[i].next)
    {
        abcd *e=edges[table[i].num];
        e->z=table[i].val;
        if(e->x==e->y) continue;
        if(Connected(tree[e->x],tree[e->y]))
        {
            Move_To_Root(tree[e->x]);
            Access(tree[e->y]);
            Splay(tree[e->x]);
            abcd *temp=tree[e->x]->max_val;
            if(temp->z <= e->z)
                continue;
            ans-=temp->z;
            Cut(temp,tree[temp->x]);
            Cut(temp,tree[temp->y]);
            operations[++top]=make_pair(0,temp);
        }
        ans+=e->z;
        Link(e,tree[e->x]);
        Link(e,tree[e->y]);
        operations[++top]=make_pair(1,e);
    }
    //a.clear();
    if(x==y)
    {
        if(mid)
            os.Put_Long_Long(ans);
    }
    else
        Divide_And_Conquer(p<<1,x,mid,ans),Divide_And_Conquer(p<<1|1,mid+1,y,ans);
    while(top>bottom)
    {
        pair<bool,abcd*> temp=operations[top--];
        if(temp.first==0)
        {
            Link(temp.second,tree[temp.second->x]);
            Link(temp.second,tree[temp.second->y]);
        }
        else
        {
            Cut(temp.second,tree[temp.second->x]);
            Cut(temp.second,tree[temp.second->y]);
        }
    }
}

int main()
{
    #ifdef PoPoQQQ
    freopen("2001.in","r",stdin);
    freopen("2001.out","w",stdout);
    #endif
    using namespace Link_Cut_Tree;
    int i,x,y,z;
    cin>>n>>m>>q;
    for(i=1;i<=n;i++)
        tree[i]=new (C++)abcd(0,0,-1);
    for(i=1;i<=m;i++)
    {
        x=IStream::Get_Int();
        y=IStream::Get_Int();
        z=IStream::Get_Int();
        edges[i]=new (C++)abcd(x,y,z);
        tim[i]=0;
    }
    for(i=1;i<=q;i++)
    {
        x=IStream::Get_Int();
        y=IStream::Get_Int();
        Insert(1,0,q,tim[x],i-1,x,edges[x]->z);
        tim[x]=i;edges[x]->z=y;
    }
    for(i=1;i<=m;i++)
        Insert(1,0,q,tim[i],q,i,edges[i]->z);
    Divide_And_Conquer(1,0,q,0);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章