您的位置:首页 > 其它

【BZOJ】3732 Network 最小生成树+LCA

2017-06-09 20:32 585 查看
题目传送门

挺有意思的一道题呢……至少,最小生成树+LCA的思想就非常棒。

首先,对于所有给出的边做一遍最小生成树,删去最小生成树以外的边。

然后,将最小生成树这棵无根树转化成有根树,当然还是树的重心。

在建立有根树的同时记录当前节点倍增到当前祖先路径上的最大值。

最后,对于每一次询问,做一遍LCA,同时统计所有倍增时的最大值,即为答案。

附上AC代码:

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#define N 15010
using namespace std;

struct note{
int x,y,w;
bool operator < (const note lyf) const {return w<lyf.w;}
}a[N<<1];
struct side{
int to,w,nt;
}s[N<<1];
int n,m,q,fa
,fx,fy,h
,num,size
,mx
,rt,d
,f
[15],k,f_max
[15],x,y;

inline char nc(){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
a*=f;return;
}

inline int gf(int x){
return !fa[x]||x==fa[x]?x:fa[x]=gf(fa[x]);
}

inline void add(int x,int y,int w){
s[++num]=(side){y,w,h[x]},h[x]=num;
s[++num]=(side){x,w,h[y]},h[y]=num;
}

inline void so(int x,int fa){
size[x]=1,mx[x]=0;
for (int i=h[x]; i; i=s[i].nt)
if (s[i].to!=fa)
so(s[i].to,x),size[x]+=size[s[i].to],mx[x]=max(mx[x],size[s[i].to]);
mx[x]=max(mx[x],n-size[x]);
if (mx[x]<mx[rt]) rt=x;
return;
}

inline void build(int x){
d[x]=d[f[x][0]]+1;
for (int i=h[x]; i; i=s[i].nt)
if (s[i].to!=f[x][0])
f[s[i].to][0]=x,f_max[s[i].to][0]=s[i].w,build(s[i].to);
return;
}

inline int query(int x,int y){
if (d[x]<d[y]) swap(x,y);
int ans=0;
for (int i=k; i>=0; --i)
if (d[f[x][i]]>=d[y]) ans=max(ans,f_max[x][i]),x=f[x][i];
if (x==y) return ans;
for (int i=k; i>=0; --i)
if (f[x][i]!=f[y][i]){
ans=max(ans,max(f_max[x][i],f_max[y][i]));
x=f[x][i],y=f[y][i];
}
ans=max(ans,max(f_max[x][0],f_max[y][0]));
return ans;
}

int main(void){
read(n),read(m),read(q);
for (int i=1; i<=m; ++i) read(a[i].x),read(a[i].y),read(a[i].w);
sort(a+1,a+1+m);
for (int i=1; i<=m; ++i){
fx=gf(a[i].x),fy=gf(a[i].y);
if (fx!=fy) fa[fx]=fy,add(a[i].x,a[i].y,a[i].w);
}
mx[0]=n,so(1,0),build(rt);
for (int j=1; j<=(k=log(n)/log(2)+1); ++j)
for (int i=1; i<=n; ++i)
f[i][j]=f[f[i][j-1]][j-1],f_max[i][j]=max(f_max[i][j-1],f_max[f[i][j-1]][j-1]);
while (q--){
read(x),read(y);
printf("%d\n",query(x,y));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: