NOIP2013 Day1 T3 货车运输

竟然一次A掉了...

首先用kruskal构建一颗最大生成树。(因为要使最小边最大,则这条边一定在最大生成树上)

于是每次询问就转变为在一棵树上询问两点到LCA的最小边权,用倍增法解决。

顺便复习了一下并查集写法。。。T_T




#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define LL long long
#define pa pair
#define MAXN 10005
#define MAXM 50005
#define INF 1000000000
using namespace std;
int n,m,q,x,y,cnt=0;
int p[MAXN],d[MAXN],ver[MAXM*2],head[MAXN],f[MAXN][20],g[MAXN][20];
bool vst[MAXN];
struct edge_type
{
	int next,to,w;
}e[MAXN*2];
struct data
{
	int x,y,z;
}a[MAXM];
int read()
{
	int ret=0,flag=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') {ret=ret*10+ch-'0';ch=getchar();}
	return ret*flag;
}
void add_edge(int u,int v,int w)
{
	e[++cnt].to=v;
	e[cnt].next=head[u];
	e[cnt].w=w;
	head[u]=cnt;
}
void dfs(int x,int dep)
{
	vst[x]=true;
	d[x]=dep;
	for(int i=head[x];i;i=e[i].next) if (!vst[e[i].to])
	{
		f[e[i].to][0]=x;
		g[e[i].to][0]=e[i].w;
		dfs(e[i].to,dep+1);
	}
}
bool cmp(data d1,data d2)
{
	return d1.z>d2.z;
}
int find(int x)
{
	if (p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
void kruskal()
{
	sort(a+1,a+m+1,cmp);
	F(i,1,n) p[i]=i;
	F(i,1,m)
	{
		int fx=find(a[i].x),fy=find(a[i].y);
		if (fx==fy) continue;
		p[fx]=fy;
		add_edge(a[i].x,a[i].y,a[i].z);
		add_edge(a[i].y,a[i].x,a[i].z);
	}
}
int lca_min(int a,int b)
{
	if (a==b) return 0;
	int ret=INF;
	if (d[a]=d[b])
	{
		ret=min(ret,g[a][i]);
		a=f[a][i];
	}
	if (a==b) return ret;
	D(i,k,0) if (f[a][i]&&f[a][i]!=f[b][i])
	{
		ret=min(ret,min(g[a][i],g[b][i]));
		a=f[a][i];
		b=f[b][i];
	}
	ret=min(ret,min(g[a][0],g[b][0]));
	return ret;
}
int main()
{
	memset(head,0,sizeof(head));
	memset(vst,false,sizeof(vst));
	memset(f,0,sizeof(f));
	memset(g,127,sizeof(g));
	n=read();m=read();
	F(i,1,m) {a[i].x=read();a[i].y=read();a[i].z=read();}
	q=read();
	kruskal();
	dfs(1,1);
	for(int j=1;(1<


你可能感兴趣的:(生成树,倍增,LCA)