您的位置:首页 > 其它

[BZOJ1787][AHOI2008]Meet 紧急集合(LCA)

2016-04-02 17:54 441 查看

题目描述

传送门

题解

两两求lca,如果有两个相同,另外一个就是要到达的点。

求lca很好理解,因为这个点一定要在这些点两两之间的唯一路径上,如果去别的点的话就太蠢了。

如果两对lca相同,那么说明有两个点到这个lca的路需要走重复的一段,那么我们就不要这么蠢,让另外一个点自己走这段路就好了。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int max_n=5e5+5;
const int max_e=max_n*2;
const int sz=19;

int n,m,x,y,z,other,goal,ans;
int tot,point[max_n],next[max_e],v[max_e];
int f[max_n][sz],s[max_n][sz];
int h[max_n],mi[sz];
struct hp{
int r,sum;
};
hp r1,r2,r3;

inline void addedge(int x,int y){
++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}

inline void dfs(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]=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]=1;
dfs(v[i],x,dep+1);
}
}

inline hp lca(int x,int y){
hp ans;
int sum=0;
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)
sum+=s[x][i],x=f[x][i];
if (x==y) return ans=(hp){x,sum};
for (int i=sz-1;i>=0;--i)
if (f[x][i]!=f[y][i]){
sum+=s[x][i]+s[y][i];
x=f[x][i],y=f[y][i];
}
sum+=s[x][0]+s[y][0];
return ans=(hp){f[x][0],sum};
}

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){
scanf("%d%d",&x,&y);
addedge(x,y);
}
dfs(1,0,1);
for (int i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
r1=lca(x,y);
r2=lca(y,z);
r3=lca(x,z);
if (r1.r==r2.r) other=y,goal=r3.r,ans=r3.sum;
else if (r2.r==r3.r) other=z,goal=r1.r,ans=r1.sum;
else if (r1.r==r3.r) other=x,goal=r2.r,ans=r2.sum;
ans+=lca(other,goal).sum;
printf("%d %d\n",goal,ans);
}
}


总结

①看清楚数据范围!别再RE了!

②倍增维护一个值时,lca先更新答案再蹦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: