(题目描述略)
算法思路:先求原图最大生成树,再用树链剖分,套 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 aint 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<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"%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;i2*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<for(int j=1;(1<1][j],ST[i-1][(1<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;
}