[NOIP2013][CODEVS3287]货车运输(kruskal+树上倍增)

题目描述

传送门

题解

很久之前写的,发现没有发题解,于是来写一发。
用kruskal求最大生成树,然后倍增。
现在看当时的码风都非常的naive~
还有发现自己用了poj当做变量名= =吓哭了T_T

代码

#include<algorithm> 
#include<iostream> 
#include<cstring> 
#include<cstdio> 
#define MAXN 50005 
#define sz 13 
#define maxn 10005 
#define large 2100000000 
using namespace std;  
int n,m,sum,r,tot,x,y,p;  
int father[maxn],ccount[maxn],root[maxn],point[maxn],next[2*MAXN],v[2*MAXN],c[2*MAXN],h[maxn],mi[sz],f[maxn][sz],s[maxn][sz];  
struct hp{  
 int left,right,delta; 
}a[MAXN];  
int cmp(hp a,hp b){  
 return a.delta>b.delta; 
}  
int find(int x){  
 if (x==father[x]) return x; father[x]=find(father[x]); return father[x]; 
}  
void merge(int x,int y){  
 int f1=find(x); int f2=find(y); father[f1]=f2; 
}  
inline void add(int x,int y,int z,int i){  
 v[i]=y; c[i]=z; next[i]=point[x]; point[x]=i; 
}  
inline void build(int x,int fa,int dep){  
 h[x]=dep; 
 for (int i=1;i<sz;++i){ 
 if (h[x]-mi[i]<1) break; 
 f[x][i]=f[f[x][i-1]][i-1]; 
 s[x][i]=min(s[x][i-1],s[f[x][i-1]][i-1]); 
 } 
 for (int i=point[x];i;i=next[i]) 
 if (v[i]!=fa){ 
 f[v[i]][0]=x; 
 s[v[i]][0]=c[i]; 
 build(v[i],x,dep+1); 
 } 
}  
inline int lca(int x,int y){  
 int Min=large; 
 if (h[x]<h[y]) swap(x,y); int k=h[x]-h[y]; 
 for (int i=0;i<sz;++i) 
 if ((k>>i)&1){ 
 Min=min(Min,s[x][i]); x=f[x][i]; 
 } 
 if (x==y) return Min; 
 for (int i=sz-1;i>=0;--i) 
 if (f[x][i]!=f[y][i]){ 
 Min=min(Min,min(s[x][i],s[y][i])); 
 x=f[x][i]; y=f[y][i]; 
 } 
 Min=min(Min,min(s[x][0],s[y][0])); 
 return Min; 
}  
int main(){  
 scanf("%d%d",&n,&m); 
 mi[0]=1; for (int i=1;i<sz;++i) mi[i]=mi[i-1]*2; 
 for (int i=1;i<=n;++i) father[i]=i; 
 for (int i=1;i<=m;++i){ 
 scanf("%d%d%d",&a[i].left,&a[i].right,&a[i].delta); 
 if (find(a[i].left)!=find(a[i].right)) merge(a[i].left,a[i].right); 
 } 
 for (int i=1;i<=n;++i) int poj=find(i); 
 for (int i=1;i<=n;++i) ++ccount[father[i]]; 
 for (int i=1;i<=n;++i) 
 if (ccount[i]){ 
 sum+=ccount[i]-1; root[++r]=i; 
 } 
 sort(a+1,a+m+1,cmp); 
 for (int i=1;i<=n;++i) father[i]=i; int i=0; 
 while(tot<sum){ 
 i++; 
 if (find(a[i].left)!=find(a[i].right)){ 
 add(a[i].left,a[i].right,a[i].delta,(++tot)<<1); 
 add(a[i].right,a[i].left,a[i].delta,tot<<1|1); 
 merge(a[i].left,a[i].right); 
 } 
 } 
 memset(s,127/3,sizeof(s)); 
 for (int i=1;i<=r;++i){ 
 int tmp=root[i]; build(tmp,0,1); 
 } 
 scanf("%d",&p); 
 for (int i=1;i<=p;++i){ 
 scanf("%d%d",&x,&y); 
 if (find(x)!=find(y)){ 
 printf("-1\n");continue; 
 } 
 int ans=lca(x,y);printf("%d\n",ans); 
 } 
}  

你可能感兴趣的:(kruskal,noip,codevs,倍增)