您的位置:首页 > 其它

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

2016-04-02 18:47 513 查看

题目描述

传送门

题解

很久之前写的,发现没有发题解,于是来写一发。

用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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: