NOIP2013D1T3 貨車運輸 題解

(題目描述略)

算法思路:先求原圖最大生成樹,再用樹鏈剖分,套 ST 表求 RMQ 即可。

求最大生成樹可用 Kruskal 算法,用帶路徑壓縮的並查集維護。

做樹鏈剖分時將樹從邊表示轉爲左兒子右兄弟表示,這和鏈式前向星表示是等價的。

注意圖有可能不連通,在這種情況下生成多棵最大生成樹,相應的表示法也要轉換。可用並查集判斷兩點是否連通。

代碼如下:

#include"math.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#define exchange(a,b) ((a)^=(b)^=(a)^=(b))
bool opt[10005];
int city[10005],ST[15][10005],totp=1,vertex[10005];
struct ROAD
{
    int x,y,z;
}road[50005];
struct E
{
    int next,power,to;
}edge[20005];
struct ChainTree_Node
{
    int dep,fa,gfa,posi,siz,son;
}CTree[10005];
int intmin(int a,int b)
{
    return a<b?a:b;
}
int cmp(const void *p,const void *q)
{
    return (*(ROAD *)p).z<(*(ROAD *)q).z?1:-1;
}
int cityfind(int now)
{
    if(city[now]==-1)
        return now;
    return city[now]=cityfind(city[now]);
}
void edgemake(int fr,int to,int power,int stript)
{
    edge[stript].next=vertex[fr];
    edge[stript].power=power;
    edge[stript].to=to;
    vertex[fr]=stript;
}
void CT_dfs0(int now)
{
    opt[now]=false;
    if(vertex[now]==-1)
        return;
    if(CTree[now].fa==edge[vertex[now]].to)
        vertex[now]=edge[vertex[now]].next;
    else
        for(int i=vertex[now];edge[i].next>-1;i=edge[i].next)
            if(CTree[now].fa==edge[edge[i].next].to)
                edge[i].next=edge[edge[i].next].next;
    for(int i=vertex[now];i>-1;i=edge[i].next)
        CTree[edge[i].to].fa=now,
        CT_dfs0(edge[i].to);
}
void CT_dfs1(int now)
{
    CTree[now].dep=CTree[CTree[now].fa].dep+1;
    CTree[now].siz=1;
    CTree[now].son=0;
    for(int i=vertex[now];i>-1;i=edge[i].next)
    {
        CT_dfs1(edge[i].to);
        CTree[now].siz+=CTree[edge[i].to].siz;
        if(CTree[edge[i].to].siz>CTree[CTree[now].son].siz)
            CTree[now].son=edge[i].to;
    }
}
void CT_dfs2(int now)
{
    if(vertex[now]==-1)
    {
        CTree[now].son=now;
        return;
    }
    for(int i=vertex[now];i>-1;i=edge[i].next)
        if(CTree[now].son==edge[i].to)
            CTree[edge[i].to].gfa=CTree[now].gfa,
            CTree[edge[i].to].posi=totp,
            ST[0][totp++]=edge[i].power,
            CT_dfs2(edge[i].to);
    for(int i=vertex[now];i>-1;i=edge[i].next)
        if(CTree[now].son!=edge[i].to)
            CTree[edge[i].to].gfa=edge[i].to,
            CTree[edge[i].to].posi=totp,
            ST[0][totp++]=edge[i].power,
            CT_dfs2(edge[i].to);
}
int ST_QueryMin(int ql,int qr)
{
    int temp=(int)(log((double)(qr-ql+1))/log(2.000000));
    return intmin(ST[temp][ql],ST[temp][qr-(1<<temp)+1]);
}
int CT_QueryMin(int u,int v)
{
    if(CTree[CTree[u].gfa].dep>CTree[CTree[v].gfa].dep)
        exchange(u,v);
    if(CTree[u].gfa!=CTree[v].gfa)
        return intmin(intmin(v!=CTree[v].gfa?ST_QueryMin(CTree[CTree[CTree[v].gfa].son].posi,CTree[v].posi):0x7FFFFFFF,
            ST_QueryMin(CTree[CTree[v].gfa].posi,CTree[CTree[v].gfa].posi)),
            CT_QueryMin(u,CTree[CTree[v].gfa].fa));
    if(CTree[u].dep>CTree[v].dep)
        exchange(u,v);
    if(u!=v)
        return ST_QueryMin(CTree[CTree[u].son].posi,CTree[v].posi);
    return 0x7FFFFFFF;
}
int main()
{
    freopen("truck.in","r",stdin);
    freopen("truck.out","w",stdout);
    int m,n,q,x=0,y;
    scanf("%d %d",&n,&m);
    for(int i=0;i<m;i++)
        scanf("%d %d %d",&road[i].x,&road[i].y,&road[i].z);
    qsort(road,m,sizeof(ROAD),cmp);
    memset(city,-1,sizeof(city));
    memset(vertex,-1,sizeof(vertex));
    for(int i=0;i<m&&x<2*n-2;i++)
        if(cityfind(road[i].x)==-1||cityfind(road[i].x)!=cityfind(road[i].y))
            city[cityfind(road[i].x)]=cityfind(road[i].y),
            edgemake(road[i].x,road[i].y,road[i].z,x++),
            edgemake(road[i].y,road[i].x,road[i].z,x++);
    CTree[0].dep=CTree[0].siz=0;
    memset(opt,true,sizeof(opt));
    for(int i=1;i<=n;i++)
        if(opt[i])
            CTree[i].fa=CTree[i].posi=0,
            CTree[i].gfa=i,
            CT_dfs0(i),
            CT_dfs1(i),
            CT_dfs2(i);
    for(int i=1;1<<i<totp;i++)
        for(int j=1;(1<<i)+j<=totp;j++)
            ST[i][j]=intmin(ST[i-1][j],ST[i-1][(1<<i-1)+j]);
    scanf("%d",&q);
    while(q--)
        scanf("%d %d",&x,&y),
        printf("%d\n",cityfind(x)==cityfind(y)?CT_QueryMin(x,y):-1);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章