把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P1967 货车运输

题面传送门
显然不可以最长路。
司机肯定喜欢走长的路径,所以先把最大生成树跑出来。
然后再最大生成树上跑倍增不就好了?
代码实现:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,ans,flag[10039],f[10039],fa[10039][20],minn[10039][20],d[10039],lg[10039],tots,un,wn,w[10039];
struct yyy{int to,w,z;};
struct ljb{
	int head,h[10039];
	yyy f[200039];
	inline void add(int x,int y,int z){
		f[++head]=(yyy){y,z,h[x]};
		h[x]=head;
	}
}s;
struct question{int x,y,z;}sf[200039];
inline bool cmp(question x,question y){return x.z>y.z;}
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline void dfs(int x,int last){
	d[x]=d[last]+1;
	fa[x][0]=last;
	minn[x][0]=w[x];
	for(int i=1;i<=lg[d[x]];i++) fa[x][i]=fa[fa[x][i-1]][i-1],minn[x][i]=min(minn[x][i-1],minn[fa[x][i-1]][i-1]);
	int cur=s.h[x];
	yyy tmp;
	while(cur!=-1){
		tmp=s.f[cur];
		if(tmp.to!=last) w[tmp.to]=tmp.w,dfs(tmp.to,x);
		cur=tmp.z;
	}
}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline int lca(int x,int y){
	int ans=1e9;
	if(d[x]<d[y]) swap(x,y);
	while(d[x]>d[y]) ans=min(ans,minn[x][lg[d[x]-d[y]]-1]),x=fa[x][lg[d[x]-d[y]]-1];
	if(x==y) return ans;
	for(int k=lg[d[x]]-1;k>=0;k--) if(fa[x][k]!=fa[y][k]) ans=min(ans,min(minn[x][k],minn[y][k])),x=fa[x][k],y=fa[y][k];
	return min(ans,min(minn[x][0],minn[y][0]));
}
int main(){
	register int i,j;
	memset(s.h,-1,sizeof(s.h));
	memset(minn,0x3f,sizeof(minn));
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) f[i]=i;
	for(i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	for(i=1;i<=m;i++){
		scanf("%d%d%d",&sf[i].x,&sf[i].y,&sf[i].z);
		un=find(sf[i].x);wn=find(sf[i].y);
		if(un!=wn) f[un]=wn;
	}
	for(i=1;i<=n;i++){
		flag[find(i)]++;
		if(flag[find(i)]==1) ans++;
	}
	for(i=1;i<=n;i++) f[i]=i;
	sort(sf+1,sf+m+1,cmp);
	for(i=1;i<=m;i++){
		un=find(sf[i].x);wn=find(sf[i].y);
		if(un!=wn){
			f[un]=wn;
			tots++;
			s.add(sf[i].x,sf[i].y,sf[i].z);
			s.add(sf[i].y,sf[i].x,sf[i].z);
			//printf("%d %d %d\n",sf[i].x,sf[i].y,sf[i].z);
			if(tots==n-ans) break;
		}
	}
	w[1]=1e9;
	dfs(1,1);
	/*for(i=1;i<=n;i++){
		for(j=0;j<=lg[d[i]];j++) printf("%d ",fa[i][j]);
		printf("\n");
	}*/
	scanf("%d",&k);
	for(i=1;i<=k;i++){
		scanf("%d%d",&x,&y);
		if(find(x)!=find(y)) printf("-1\n");
		else printf("%d\n",lca(x,y));
	}
}
posted @ 2020-07-04 21:53  275307894a  阅读(26)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end