NOIP2013 货车运输 LCA倍增+最大生成树

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1e4+;
const int INF=0x3f3f3f3f;
struct Edge{
int u,v,w,next;
bool operator<(const Edge &rhs)const{
return w>rhs.w;
}
}o[N*],edge[N<<];
int fa[N][],fat[N],head[N],tot,p[N][];
void add(int u,int v,int w){
edge[tot].w=w;
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int find(int x){
if(x==fat[x])return x;
return fat[x]=find(fat[x]);
}
int d[N];
void dfs(int u,int f){
d[u]=d[f]+;
fa[u][]=f;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==f)continue;
dfs(v,u);
p[v][]=edge[i].w;
}
}
int lca(int u,int v){
int ans=INF;
if(d[u]<d[v])swap(u,v);
for(int t=d[u]-d[v],i=;t;t>>=,++i)
if(t&)ans=min(p[u][i],ans),u=fa[u][i];
if(u==v)return ans;
for(int i=;i>=;--i){
if(fa[u][i]!=-&&fa[u][i]!=fa[v][i]){
ans=min(ans,p[u][i]);
ans=min(ans,p[v][i]);
u=fa[u][i],v=fa[v][i];
}
}
ans=min(ans,p[u][]);
ans=min(ans,p[v][]);
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=m;++i){
scanf("%d%d%d",&o[i].u,&o[i].v,&o[i].w);
}
sort(o+,o++m);
for(int i=;i<=n;++i)fat[i]=i,head[i]=-;
int cnt=;
for(int i=;i<=m;++i){
int x=find(o[i].u),y=find(o[i].v);
if(x!=y){
fat[y]=x;
++cnt;
add(o[i].u,o[i].v,o[i].w);
add(o[i].v,o[i].u,o[i].w);
if(cnt>=n-)break;
}
}
memset(p,INF,sizeof(p));
memset(fa,-,sizeof(fa));
for(int i=;i<=n;++i){
if(fat[i]==i){
dfs(i,);
fa[i][]=-;
}
}
for(int j=;(<<j)<=n;++j){
for(int i=;i<=n;++i){
if(fa[i][j-]!=-)
{
fa[i][j]=fa[fa[i][j-]][j-];
p[i][j]=min(p[i][j-],p[fa[i][j-]][j-]);
}
}
}
int q;
scanf("%d",&q);
while(q--){
int u,v;
scanf("%d%d",&u,&v);
if(find(u)!=find(v)){
printf("-1\n");
continue;
}
printf("%d\n",lca(u,v));
}
return ;
}

分析:

看这个就好http://hzwer.com/1344.html 仰慕黄学长

然后刚开始我没想写倍增,想写树剖的,后来一看,树剖勉强应该多一个log,而且代码长

所以倍增大法好

上一篇:ios开发中一些常用API总结


下一篇:js-比较两个日期的大小