BUAA 415 合并果子(并查集+二叉堆)

题目链接:http://acm.buaa.edu.cn/problem/415/

题意:n个数,每次合并两个数,代价为这两个数的和。已知在第i次合并前有一些修改。每次合并时合并两个最小的数字。问最后的代价为多少?

思路:维护一个小根堆,记录每一个数在堆中的编号。








struct node

{

    int id;

    i64 cnt;

};



struct Event

{

    int id,det;



    Event(){}

    Event(int _id,int _det)

    {

        id=_id;

        det=_det;

    }

};





const i64 INF=1e18;

const int MAX=10005;

node T[MAX];

int n,A,B,p[MAX];

vector<Event> V[MAX];



int C;



int Set[MAX];



void setInit(int n)

{

    int i;

    FOR1(i,n) Set[i]=i;

}



int setFind(int x)

{

    if(Set[x]!=x) Set[x]=setFind(Set[x]);

    return Set[x];

}







void down(int x)

{

    int L,R,t;

    node temp;

    while(1)

    {

        L=x*2;

        R=x*2+1;

        if(L<=n&&(T[L].cnt<T[x].cnt||T[L].cnt==T[x].cnt&&T[L].id<T[x].id))

        {

            t=L;

        }

        else t=x;

        if(R<=n&&(T[R].cnt<T[t].cnt||T[R].cnt==T[t].cnt&&T[R].id<T[t].id))

        {

            t=R;

        }

        if(t==x) return;

        temp=T[x];

        T[x]=T[t];

        T[t]=temp;

        p[T[t].id]=t;

        p[T[x].id]=x;

        x=t;

    }

}



void up(int x)

{

    int pre,t;

    node temp;

    while(1)

    {

        pre=x/2;

        if(pre>=1&&(T[pre].cnt>T[x].cnt||T[pre].cnt==T[x].cnt&&T[pre].id>T[x].id))

        {

            t=pre;

        }

        else t=x;

        if(t==x) return;

        temp=T[t];

        T[t]=T[x];

        T[x]=temp;

        p[T[t].id]=t;

        p[T[x].id]=x;

        x=t;

    }

}



i64 deal(int x)

{

    i64 i,ans=0,t;

    node temp;

    for(i=0;i<SZ(V[x]);i++)

    {

        t=setFind(V[x][i].id);

        t=p[t];

        T[t].cnt+=V[x][i].det;

        if(V[x][i].det<0) up(t);

        else down(t);

    }



    int preid=T[1].id;

    ans+=T[1].cnt;

    T[1]=T[n--];

    down(1);

    ans+=T[1].cnt;

    T[1].cnt=ans;



    if(preid>T[1].id) Set[preid]=T[1].id;

    else

    {

        Set[T[1].id]=preid;

        p[preid]=1;

        T[1].id=preid;

    }



    down(1);

    return ans;

}







int main()

{

    for(scanf("%d",&C);C--;)

    {

        RD(n,A,B);

        int i,j,x,y,z;

        FOR1(i,n)

        {

            RD(T[i].cnt);

            p[i]=T[i].id=i;

        }

        DOW1(i,n/2) down(i);

        FOR1(i,n) CLR(V[i]);

        FOR1(i,A)

        {

            RD(x,y,z);

            V[x].pb(Event(y,-z));

        }

        FOR1(i,B)

        {

            RD(x,y,z);

            V[x].pb(Event(y,z));

        }

        setInit(n);

        i64 ans=0,tempN=n-1;

        FOR1(i,tempN) ans+=deal(i);

        PR(ans);

    }

    return 0;

}

  

你可能感兴趣的:(并查集)